bitkeeper revision 1.1718.1.7 (42b742f8NxTuN2pqCHFAWI78dbEYKw)
authorsmh22@firebug.cl.cam.ac.uk <smh22@firebug.cl.cam.ac.uk>
Mon, 20 Jun 2005 22:28:08 +0000 (22:28 +0000)
committersmh22@firebug.cl.cam.ac.uk <smh22@firebug.cl.cam.ac.uk>
Mon, 20 Jun 2005 22:28:08 +0000 (22:28 +0000)
Initial MAC (sHype) support from IBM.
Defaults to NULL policy for now.

Signed-off-by: Reiner Sailer <sailer@us.ibm.com>
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
Signed-off-by: Steven Hand <steven@xensource.com>
36 files changed:
.rootkeys
tools/Makefile
tools/libxc/xc.h
tools/libxc/xc_domain.c
tools/policy/Makefile [new file with mode: 0644]
tools/policy/policy_tool.c [new file with mode: 0644]
tools/python/xen/lowlevel/xc/xc.c
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/image.py
tools/python/xen/xend/server/SrvDomainDir.py
tools/python/xen/xm/create.py
tools/python/xen/xm/main.py
tools/python/xen/xm/opts.py
xen/Makefile
xen/Rules.mk
xen/acm/Makefile [new file with mode: 0644]
xen/acm/acm_chinesewall_hooks.c [new file with mode: 0644]
xen/acm/acm_core.c [new file with mode: 0644]
xen/acm/acm_null_hooks.c [new file with mode: 0644]
xen/acm/acm_policy.c [new file with mode: 0644]
xen/acm/acm_simple_type_enforcement_hooks.c [new file with mode: 0644]
xen/arch/x86/setup.c
xen/arch/x86/x86_32/entry.S
xen/common/dom0_ops.c
xen/common/event_channel.c
xen/common/grant_table.c
xen/common/policy_ops.c [new file with mode: 0644]
xen/include/acm/acm_core.h [new file with mode: 0644]
xen/include/acm/acm_endian.h [new file with mode: 0644]
xen/include/acm/acm_hooks.h [new file with mode: 0644]
xen/include/public/acm.h [new file with mode: 0644]
xen/include/public/acm_dom0_setup.h [new file with mode: 0644]
xen/include/public/dom0_ops.h
xen/include/public/policy_ops.h [new file with mode: 0644]
xen/include/public/xen.h
xen/include/xen/sched.h

index 338b1be862b77faa90c6b03f40a3e27fe7e3d322..b04c5ff74bccd43ea15223fe2f1812a2452b6d24 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 41adc641dV-0cDLSyzMs5BT8nL7v3Q tools/misc/xenperf.c
 4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops
 40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
+42b742f6JFcp6LFpYu-B4AEsfQwSFw tools/policy/Makefile
+42b742f66XOdRMrwaHvbCdSSQyCrFw tools/policy/policy_tool.c
 4270cc81g3nSNYCZ1ryCMDEbLtMtbQ tools/pygrub/Makefile
 4270deeccyRsJn6jLnRh9odRtMW9SA tools/pygrub/README
 4270cc81EIl7NyaS3Av6IPRk2c2a6Q tools/pygrub/setup.py
 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
 3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
+42b742f6XHTfIEm_hUPtzjKr37LVhw xen/acm/Makefile
+42b742f6tHzn0fZWH3TjPva8gbqpow xen/acm/acm_chinesewall_hooks.c
+42b742f6bM8kZwuIUbepHZ8SQQkjJA xen/acm/acm_core.c
+42b742f6cwfrPubqH47gQpke8xkYSA xen/acm/acm_null_hooks.c
+42b742f69qSxm5MM-wtPaWtCqyI3KA xen/acm/acm_policy.c
+42b742f6VbmdlwekQRMhXugjcu9QXg xen/acm/acm_simple_type_enforcement_hooks.c
 421098b25A0RvuYN3rP28ga3_FN3_Q xen/arch/ia64/Makefile
 421098b2okIeYXS9w9avmSozls61xA xen/arch/ia64/Rules.mk
 421098b21p12UcKjHBrLh_LjlvNEwA xen/arch/ia64/acpi.c
 41a61536SZbR6cj1ukWTb0DYU-vz9w xen/common/multicall.c
 3ddb79bdD4SLmmdMD7yLW5HcUWucXw xen/common/page_alloc.c
 3e54c38dkHAev597bPr71-hGzTdocg xen/common/perfc.c
+42b742f6mgq9puEr7lUrLST0VEpsig xen/common/policy_ops.c
 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c
 41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c
 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c
 4049e6bfNSIq7s7OV-Bd69QD0RpR2Q xen/drivers/char/console.c
 4298e018XQtZkCdufpyFimOGZqqsFA xen/drivers/char/ns16550.c
 3e4a8cb7nMChlro4wvOBo76n__iCFA xen/drivers/char/serial.c
+42b742f6OteAMPWnoqxqfRX3yxD0yw xen/include/acm/acm_core.h
+42b742f6XfIijctEwA0YWL2BoWtDNg xen/include/acm/acm_endian.h
+42b742f6jXvp1vdbU2v2WJjTPku65A xen/include/acm/acm_hooks.h
 40715b2cFpte_UNWnBZW0Du7z9AhTQ xen/include/acpi/acconfig.h
 40715b2ctNvVZ058w8eM8DR9hOat_A xen/include/acpi/acexcep.h
 40715b2com8I01qcHcAw47e93XsCqQ xen/include/acpi/acglobal.h
 404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
 422f27c8RHFkePhD34VIEpMMqofZcA xen/include/asm-x86/x86_emulate.h
 400304fcmRQmDdFYEzDh0wcBba9alg xen/include/public/COPYING
+42b742f6duiOTlZvysQkRYZHYBXqvg xen/include/public/acm.h
+42b742f7TIMsQgUaNDJXp3QlBve2SQ xen/include/public/acm_dom0_setup.h
 421098b7OKb9YH_EUA_UpCxBjaqtgA xen/include/public/arch-ia64.h
 404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/public/arch-x86_32.h
 404f1bc7IwU-qnH8mJeVu0YsNGMrcw xen/include/public/arch-x86_64.h
 41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
 41ee5e8c6mLxIx82KPsbpt_uts_vSA xen/include/public/io/usbif.h
 4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
+42b742f7Lzy8SKKG25L_-fgk5FHA2Q xen/include/public/policy_ops.h
 40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
 404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
 42b5a5f2QC1IxeuwCwwsOEhvcJ2BJg xen/include/public/version.h
index 3a38e899de07c5cb3c70c72f30b76ec99eea14da..00eb4991cc3dc6556519bdb46431667dbfd39d76 100644 (file)
@@ -12,6 +12,7 @@ SUBDIRS += xcs
 SUBDIRS += xcutils
 SUBDIRS += pygrub
 SUBDIRS += firmware
+SUBDIRS += policy
 
 .PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
 
index 27e7845798cce1904088119436015ef0ad897d65..e54f9b198db6373eb52475d1f4aae58180212f5a 100644 (file)
@@ -110,6 +110,7 @@ int xc_waitdomain_core(int domain,
 
 typedef struct {
     u32           domid;
+    u32           ssidref;
     unsigned int  dying:1, crashed:1, shutdown:1, 
                   paused:1, blocked:1, running:1;
     unsigned int  shutdown_reason; /* only meaningful if shutdown==1 */
@@ -124,6 +125,7 @@ typedef struct {
 
 typedef dom0_getdomaininfo_t xc_domaininfo_t;
 int xc_domain_create(int xc_handle, 
+                     u32 ssidref,
                      u32 *pdomid);
 
 
index 8f0bba3216e5daa1f21a03037b1eefc2908250f0..2edf11c39d71b3197963c9827c547e5b1d5df5f5 100644 (file)
@@ -9,6 +9,7 @@
 #include "xc_private.h"
 
 int xc_domain_create(int xc_handle,
+                     u32 ssidref,
                      u32 *pdomid)
 {
     int err;
@@ -16,6 +17,7 @@ int xc_domain_create(int xc_handle,
 
     op.cmd = DOM0_CREATEDOMAIN;
     op.u.createdomain.domain = (domid_t)*pdomid;
+    op.u.createdomain.ssidref = ssidref;
     if ( (err = do_dom0_op(xc_handle, &op)) != 0 )
         return err;
 
@@ -101,6 +103,7 @@ int xc_domain_getinfo(int xc_handle,
             info->crashed  = 1;
         }
 
+        info->ssidref  = op.u.getdomaininfo.ssidref;
         info->nr_pages = op.u.getdomaininfo.tot_pages;
         info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT);
         info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
diff --git a/tools/policy/Makefile b/tools/policy/Makefile
new file mode 100644 (file)
index 0000000..b8d6747
--- /dev/null
@@ -0,0 +1,36 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SRCS     = policy_tool.c
+CFLAGS   += -static
+CFLAGS   += -Wall
+CFLAGS   += -Werror
+CFLAGS   += -O3
+CFLAGS   += -fno-strict-aliasing
+CFLAGS   += -I.
+
+all: build
+build: mk-symlinks
+       $(MAKE) policy_tool
+
+default: all
+
+install: all
+
+policy_tool : policy_tool.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+clean:
+       rm -rf policy_tool xen
+
+
+LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse)
+mk-symlinks:
+       [ -e xen/linux ] || mkdir -p xen/linux
+       [ -e xen/io ]    || mkdir -p xen/io
+       ( cd xen >/dev/null ; \
+         ln -sf ../$(XEN_ROOT)/xen/include/public/*.h . )
+       ( cd xen/io >/dev/null ; \
+         ln -sf ../../$(XEN_ROOT)/xen/include/public/io/*.h . )
+       ( cd xen/linux >/dev/null ; \
+         ln -sf ../../$(LINUX_ROOT)/include/asm-xen/linux-public/*.h . )
diff --git a/tools/policy/policy_tool.c b/tools/policy/policy_tool.c
new file mode 100644 (file)
index 0000000..696a70c
--- /dev/null
@@ -0,0 +1,557 @@
+/****************************************************************
+ * policy_tool.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License. 
+ *
+ * sHype policy management tool. This code runs in a domain and
+ *     manages the Xen security policy by interacting with the
+ *     Xen access control module via a /proc/xen/policycmd proc-ioctl, 
+ *     which is translated into a policy_op hypercall into Xen.
+ * 
+ * todo: implement setpolicy to dynamically set a policy cache.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+typedef uint8_t            u8;
+typedef uint16_t           u16;
+typedef uint32_t           u32;
+typedef uint64_t           u64;
+typedef int8_t             s8;
+typedef int16_t            s16;
+typedef int32_t            s32;
+typedef int64_t            s64;
+
+#include <xen/acm.h>
+
+#include <xen/policy_ops.h>
+
+#include <xen/linux/privcmd.h>
+
+#define ERROR(_m, _a...)       \
+       fprintf(stderr, "ERROR: " _m "\n" , ## _a )
+
+#define PERROR(_m, _a...) \
+       fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a ,   \
+            errno, strerror(errno))
+
+static inline int do_policycmd(int xc_handle,
+                             unsigned int cmd, 
+                             unsigned long data)
+{
+    return ioctl(xc_handle, cmd, data);
+}
+
+static inline int do_xen_hypercall(int xc_handle,
+                                   privcmd_hypercall_t *hypercall)
+{
+    return do_policycmd(xc_handle,
+                      IOCTL_PRIVCMD_HYPERCALL, 
+                      (unsigned long)hypercall);
+}
+
+static inline int do_policy_op(int xc_handle, policy_op_t *op)
+{
+    int ret = -1;
+    privcmd_hypercall_t hypercall;
+
+    op->interface_version = POLICY_INTERFACE_VERSION;
+
+    hypercall.op     = __HYPERVISOR_policy_op;
+    hypercall.arg[0] = (unsigned long)op;
+
+    if ( mlock(op, sizeof(*op)) != 0 )
+    {
+        PERROR("Could not lock memory for Xen policy hypercall");
+        goto out1;
+    }
+
+    if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+    {
+        if ( errno == EACCES )
+            fprintf(stderr, "POLICY operation failed -- need to"
+                    " rebuild the user-space tool set?\n");
+        goto out2;
+    }
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+/*************************** DUMPS *******************************/
+
+void acm_dump_chinesewall_buffer(void *buf, int buflen) {
+
+       struct acm_chwall_policy_buffer *cwbuf = (struct acm_chwall_policy_buffer *)buf;
+       domaintype_t *ssids, *conflicts, *running_types, *conflict_aggregate;
+       int i,j;
+
+       
+       if (htons(cwbuf->policy_code) != ACM_CHINESE_WALL_POLICY) {
+               printf("CHINESE WALL POLICY CODE not found ERROR!!\n");
+               return;
+       }
+       printf("\n\nChinese Wall policy:\n");
+       printf("====================\n");
+       printf("Max Types     = %x.\n", ntohs(cwbuf->chwall_max_types));
+       printf("Max Ssidrefs  = %x.\n", ntohs(cwbuf->chwall_max_ssidrefs));
+       printf("Max ConfSets  = %x.\n", ntohs(cwbuf->chwall_max_conflictsets));
+       printf("Ssidrefs Off  = %x.\n", ntohs(cwbuf->chwall_ssid_offset));
+       printf("Conflicts Off = %x.\n", ntohs(cwbuf->chwall_conflict_sets_offset));
+       printf("Runing T. Off = %x.\n", ntohs(cwbuf->chwall_running_types_offset));
+       printf("C. Agg. Off   = %x.\n", ntohs(cwbuf->chwall_conflict_aggregate_offset));
+       printf("\nSSID To CHWALL-Type matrix:\n");
+
+       ssids = (domaintype_t *)(buf + ntohs(cwbuf->chwall_ssid_offset));
+       for(i=0; i< ntohs(cwbuf->chwall_max_ssidrefs); i++) {
+               printf("\n   ssidref%2x:  ", i);
+               for(j=0; j< ntohs(cwbuf->chwall_max_types); j++)
+                       printf("%02x ", ntohs(ssids[i*ntohs(cwbuf->chwall_max_types) + j]));
+       }
+       printf("\n\nConfict Sets:\n");
+       conflicts = (domaintype_t *)(buf + ntohs(cwbuf->chwall_conflict_sets_offset));
+       for(i=0; i< ntohs(cwbuf->chwall_max_conflictsets); i++) {
+               printf("\n   c-set%2x:    ", i);
+               for(j=0; j< ntohs(cwbuf->chwall_max_types); j++)
+                       printf("%02x ", ntohs(conflicts[i*ntohs(cwbuf->chwall_max_types) +j]));
+       }
+       printf("\n");
+
+       printf("\nRunning\nTypes:         ");
+       if (ntohs(cwbuf->chwall_running_types_offset)) {
+               running_types = (domaintype_t *)(buf + ntohs(cwbuf->chwall_running_types_offset));
+               for(i=0; i< ntohs(cwbuf->chwall_max_types); i++) {
+                       printf("%02x ", ntohs(running_types[i]));
+               }
+               printf("\n");
+       } else {
+               printf("Not Reported!\n");
+       }
+       printf("\nConflict\nAggregate Set: ");
+       if (ntohs(cwbuf->chwall_conflict_aggregate_offset)) {
+               conflict_aggregate = (domaintype_t *)(buf + ntohs(cwbuf->chwall_conflict_aggregate_offset));
+               for(i=0; i< ntohs(cwbuf->chwall_max_types); i++) {
+                       printf("%02x ", ntohs(conflict_aggregate[i]));
+               }
+               printf("\n\n");
+       } else {
+               printf("Not Reported!\n");
+       }
+}
+
+void acm_dump_ste_buffer(void *buf, int buflen) {
+
+       struct acm_ste_policy_buffer *stebuf = (struct acm_ste_policy_buffer *)buf;
+       domaintype_t *ssids;
+       int i,j;
+
+       
+       if (ntohs(stebuf->policy_code) != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+               printf("SIMPLE TYPE ENFORCEMENT POLICY CODE not found ERROR!!\n");
+               return;
+       }
+       printf("\nSimple Type Enforcement policy:\n");
+       printf("===============================\n");
+       printf("Max Types     = %x.\n", ntohs(stebuf->ste_max_types));
+       printf("Max Ssidrefs  = %x.\n", ntohs(stebuf->ste_max_ssidrefs));
+       printf("Ssidrefs Off  = %x.\n", ntohs(stebuf->ste_ssid_offset));
+       printf("\nSSID To STE-Type matrix:\n");
+       
+       ssids = (domaintype_t *)(buf + ntohs(stebuf->ste_ssid_offset));
+       for(i=0; i< ntohs(stebuf->ste_max_ssidrefs); i++) {
+               printf("\n   ssidref%2x: ", i);
+               for(j=0; j< ntohs(stebuf->ste_max_types); j++)
+                       printf("%02x ", ntohs(ssids[i*ntohs(stebuf->ste_max_types) +j]));
+       }
+       printf("\n\n");
+}
+
+void acm_dump_policy_buffer(void *buf, int buflen) {
+       struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
+
+       printf("\nPolicy dump:\n");
+       printf("============\n");
+       printf("Magic     = %x.\n", ntohl(pol->magic));
+       printf("PolVer    = %x.\n", ntohl(pol->policyversion));
+       printf("Len       = %x.\n", ntohl(pol->len));
+       printf("Primary   = %s (c=%x, off=%x).\n",
+              ACM_POLICY_NAME(ntohs(pol->primary_policy_code)),
+              ntohs(pol->primary_policy_code), ntohs(pol->primary_buffer_offset));
+       printf("Secondary = %s (c=%x, off=%x).\n",
+              ACM_POLICY_NAME(ntohs(pol->secondary_policy_code)),
+              ntohs(pol->secondary_policy_code), ntohs(pol->secondary_buffer_offset));
+       switch (ntohs(pol->primary_policy_code)) {
+       case ACM_CHINESE_WALL_POLICY:
+               acm_dump_chinesewall_buffer(buf+ntohs(pol->primary_buffer_offset), 
+                                            ntohl(pol->len) - ntohs(pol->primary_buffer_offset));
+               break;
+       case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+               acm_dump_ste_buffer(buf+ntohs(pol->primary_buffer_offset), 
+                                   ntohl(pol->len) - ntohs(pol->primary_buffer_offset));
+               break;
+       case ACM_NULL_POLICY:
+               printf("Primary policy is NULL Policy (n/a).\n");
+               break;
+       default:
+               printf("UNKNOWN POLICY!\n");
+       }
+       switch (ntohs(pol->secondary_policy_code)) {
+       case ACM_CHINESE_WALL_POLICY:
+               acm_dump_chinesewall_buffer(buf+ntohs(pol->secondary_buffer_offset), 
+                                            ntohl(pol->len) - ntohs(pol->secondary_buffer_offset));
+               break;
+       case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+               acm_dump_ste_buffer(buf+ntohs(pol->secondary_buffer_offset), 
+                                   ntohl(pol->len) - ntohs(pol->secondary_buffer_offset));
+               break;
+       case ACM_NULL_POLICY:
+               printf("Secondary policy is NULL Policy (n/a).\n");
+               break;
+       default:
+               printf("UNKNOWN POLICY!\n");
+       }
+       printf("\nPolicy dump End.\n\n");
+}
+
+/*************************** set policy ****************************/
+
+int acm_domain_set_chwallpolicy(void *bufstart, int buflen) {
+#define CWALL_MAX_SSIDREFS             5
+#define CWALL_MAX_TYPES                10
+#define CWALL_MAX_CONFLICTSETS         2
+
+     struct acm_chwall_policy_buffer *chwall_bin_pol = (struct acm_chwall_policy_buffer *)bufstart;
+     domaintype_t *ssidrefs, *conflicts;
+     int ret = 0;
+     int i,j;
+
+     chwall_bin_pol->chwall_max_types = htons(CWALL_MAX_TYPES);
+     chwall_bin_pol->chwall_max_ssidrefs = htons(CWALL_MAX_SSIDREFS);
+     chwall_bin_pol->policy_code = htons(ACM_CHINESE_WALL_POLICY);
+     chwall_bin_pol->chwall_ssid_offset = htons(sizeof(struct acm_chwall_policy_buffer));
+     chwall_bin_pol->chwall_max_conflictsets = htons(CWALL_MAX_CONFLICTSETS);
+     chwall_bin_pol->chwall_conflict_sets_offset =
+        htons(
+            ntohs(chwall_bin_pol->chwall_ssid_offset) + 
+            sizeof(domaintype_t)*CWALL_MAX_SSIDREFS*CWALL_MAX_TYPES);
+     chwall_bin_pol->chwall_running_types_offset = 0; /* not set */
+     chwall_bin_pol->chwall_conflict_aggregate_offset = 0; /* not set */
+     ret += sizeof(struct acm_chwall_policy_buffer);
+     /* now push example ssids into the buffer (max_ssidrefs x max_types entries) */
+     /* check buffer size */
+     if ((buflen - ret) < (CWALL_MAX_TYPES*CWALL_MAX_SSIDREFS*sizeof(domaintype_t)))
+                          return -1; /* not enough space */
+
+     ssidrefs = (domaintype_t *)(bufstart+ntohs(chwall_bin_pol->chwall_ssid_offset));
+     for(i=0; i< CWALL_MAX_SSIDREFS; i++) {
+            for (j=0; j< CWALL_MAX_TYPES; j++)
+                    ssidrefs[i*CWALL_MAX_TYPES + j] = htons(0);
+            /* here, set type i for ssidref i; generally, a ssidref can have multiple chwall types */
+            if (i < CWALL_MAX_SSIDREFS)
+                    ssidrefs[i*CWALL_MAX_TYPES + i] = htons(1);
+     }
+     ret += CWALL_MAX_TYPES*CWALL_MAX_SSIDREFS*sizeof(domaintype_t);
+     if ((buflen - ret) < (CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES*sizeof(domaintype_t)))
+                          return -1; /* not enough space */
+
+     /* now the chinese wall policy conflict sets*/
+     conflicts = (domaintype_t *)(bufstart + 
+                                 ntohs(chwall_bin_pol->chwall_conflict_sets_offset));
+     memset((void *)conflicts, 0, CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES*sizeof(domaintype_t));
+     /* just 1 conflict set [0]={2,3}, [1]={0,5,6} */
+     if (CWALL_MAX_TYPES > 3) {
+            conflicts[2] = htons(1); conflicts[3] = htons(1); /* {2,3} */
+            conflicts[CWALL_MAX_TYPES] = htons(1); conflicts[CWALL_MAX_TYPES+5] = htons(1); 
+            conflicts[CWALL_MAX_TYPES+6] = htons(1);/* {0,5,6} */
+     }
+     ret += sizeof(domaintype_t)*CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES;
+     return ret;
+}
+
+int acm_domain_set_stepolicy(void *bufstart, int buflen) {
+#define STE_MAX_SSIDREFS       5
+#define STE_MAX_TYPES                  5
+       
+    struct acm_ste_policy_buffer *ste_bin_pol = (struct acm_ste_policy_buffer *)bufstart;
+    domaintype_t *ssidrefs;
+    int i,j, ret = 0;
+
+    ste_bin_pol->ste_max_types = htons(STE_MAX_TYPES);
+    ste_bin_pol->ste_max_ssidrefs = htons(STE_MAX_SSIDREFS);
+    ste_bin_pol->policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+    ste_bin_pol->ste_ssid_offset = htons(sizeof(struct acm_ste_policy_buffer));
+    ret += sizeof(struct acm_ste_policy_buffer);
+    /* check buffer size */
+    if ((buflen - ret) < (STE_MAX_TYPES*STE_MAX_SSIDREFS*sizeof(domaintype_t)))
+           return -1; /* not enough space */
+
+     ssidrefs = (domaintype_t *)(bufstart+ntohs(ste_bin_pol->ste_ssid_offset));
+     for(i=0; i< STE_MAX_SSIDREFS; i++) {
+            for (j=0; j< STE_MAX_TYPES; j++)
+                    ssidrefs[i*STE_MAX_TYPES + j] = htons(0);
+            /* set type i in ssidref 0 and ssidref i */
+            ssidrefs[i] = htons(1); /* ssidref 0 has all types set */
+            if (i < STE_MAX_SSIDREFS)
+                    ssidrefs[i*STE_MAX_TYPES + i] = htons(1);
+     }
+     ret += STE_MAX_TYPES*STE_MAX_SSIDREFS*sizeof(domaintype_t);
+     return ret;
+}
+
+#define MAX_PUSH_BUFFER        16384
+u8 push_buffer[MAX_PUSH_BUFFER];
+
+int acm_domain_setpolicy(int xc_handle)
+{
+     int ret;
+     struct acm_policy_buffer *bin_pol;
+     policy_op_t op;
+
+     /* future: read policy from file and set it */
+     bin_pol = (struct acm_policy_buffer *)push_buffer;
+     bin_pol->magic = htonl(ACM_MAGIC);
+     bin_pol->policyversion = htonl(POLICY_INTERFACE_VERSION);
+     bin_pol->primary_policy_code = htons(ACM_CHINESE_WALL_POLICY);
+     bin_pol->secondary_policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+
+     bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
+     bin_pol->primary_buffer_offset = htons(ntohl(bin_pol->len));
+     ret = acm_domain_set_chwallpolicy(push_buffer + ntohs(bin_pol->primary_buffer_offset), 
+                                      MAX_PUSH_BUFFER - ntohs(bin_pol->primary_buffer_offset));
+     if (ret < 0) {
+            printf("ERROR creating chwallpolicy buffer.\n");
+            return -1;
+     }
+     bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+     bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+     ret = acm_domain_set_stepolicy(push_buffer + ntohs(bin_pol->secondary_buffer_offset), 
+                                   MAX_PUSH_BUFFER - ntohs(bin_pol->secondary_buffer_offset));
+     if (ret < 0) {
+            printf("ERROR creating chwallpolicy buffer.\n");
+            return -1;
+     }
+     bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+
+     /* dump it and then push it down into xen/acm */
+     acm_dump_policy_buffer(push_buffer, ntohl(bin_pol->len));
+     op.cmd = POLICY_SETPOLICY;
+     op.u.setpolicy.pushcache = (void *)push_buffer;
+     op.u.setpolicy.pushcache_size = ntohl(bin_pol->len);
+     op.u.setpolicy.policy_type = ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+     ret = do_policy_op(xc_handle, &op);
+
+     if (ret)
+            printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
+     else
+            printf("Successfully changed policy.\n");
+     return ret;
+}
+
+/******************************* get policy ******************************/
+
+#define PULL_CACHE_SIZE                8192
+u8 pull_buffer[PULL_CACHE_SIZE];
+int acm_domain_getpolicy(int xc_handle)
+{
+     policy_op_t op;
+     int ret;
+
+     memset(pull_buffer, 0x00, sizeof(pull_buffer));
+     op.cmd = POLICY_GETPOLICY;
+     op.u.getpolicy.pullcache = (void *)pull_buffer;
+     op.u.getpolicy.pullcache_size = sizeof(pull_buffer);
+     ret = do_policy_op(xc_handle, &op);
+     /* dump policy  */
+     acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer));
+     return ret;
+}
+
+/************************ load binary policy ******************************/
+
+int acm_domain_loadpolicy(int xc_handle,
+                          const char *filename)
+{
+     struct stat mystat;
+     int ret, fd;
+     off_t len;
+     u8 *buffer;
+
+     if ((ret = stat(filename, &mystat))) {
+            printf("File %s not found.\n",filename);
+            goto out;
+     }
+
+     len = mystat.st_size;
+     if ((buffer = malloc(len)) == NULL) {
+            ret = -ENOMEM;
+            goto out;
+     }
+     if ((fd = open(filename, O_RDONLY)) <= 0) {
+            ret = -ENOENT;
+            printf("File %s not found.\n",filename);
+            goto free_out;
+     }
+     if (len == read(fd, buffer, len)) {
+            policy_op_t op;
+            /* dump it and then push it down into xen/acm */
+            acm_dump_policy_buffer(buffer, len);
+            op.cmd = POLICY_SETPOLICY;
+            op.u.setpolicy.pushcache = (void *)buffer;
+            op.u.setpolicy.pushcache_size = len;
+            op.u.setpolicy.policy_type = ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+            ret = do_policy_op(xc_handle, &op);
+                     
+            if (ret)
+                    printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
+            else
+                    printf("Successfully changed policy.\n");
+                     
+     } else {
+            ret = -1;
+     }
+     close(fd);
+ free_out:
+     free(buffer);
+ out:
+     return ret;
+}
+
+/************************ dump hook statistics ******************************/
+void 
+dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
+{
+    printf("STE-Policy Security Hook Statistics:\n");
+    printf("ste: event_channel eval_count      = %d\n", ntohl(ste_stats->ec_eval_count));
+    printf("ste: event_channel denied_count    = %d\n", ntohl(ste_stats->ec_denied_count)); 
+    printf("ste: event_channel cache_hit_count = %d\n", ntohl(ste_stats->ec_cachehit_count));
+    printf("ste:\n");
+    printf("ste: grant_table   eval_count      = %d\n", ntohl(ste_stats->gt_eval_count));
+    printf("ste: grant_table   denied_count    = %d\n", ntohl(ste_stats->gt_denied_count)); 
+    printf("ste: grant_table   cache_hit_count = %d\n", ntohl(ste_stats->gt_cachehit_count));
+}
+
+#define PULL_STATS_SIZE                8192
+int acm_domain_dumpstats(int xc_handle)
+{
+    u8 stats_buffer[PULL_STATS_SIZE];
+    policy_op_t op;
+    int ret;
+    struct acm_stats_buffer *stats;
+
+    memset(stats_buffer, 0x00, sizeof(stats_buffer));
+    op.cmd = POLICY_DUMPSTATS;
+    op.u.dumpstats.pullcache = (void *)stats_buffer;
+    op.u.dumpstats.pullcache_size = sizeof(stats_buffer);
+    ret = do_policy_op(xc_handle, &op);
+
+    if (ret < 0) {
+       printf("ERROR dumping policy stats. Use 'xm dmesg' to see details.\n"); 
+       return ret;
+    }
+    stats = (struct acm_stats_buffer *)stats_buffer;
+
+    printf("\nPolicy dump:\n");
+    printf("============\n");
+    printf("Magic     = %x.\n", ntohl(stats->magic));
+    printf("PolVer    = %x.\n", ntohl(stats->policyversion));
+    printf("Len       = %x.\n", ntohl(stats->len));
+
+    switch(ntohs(stats->primary_policy_code)) {
+    case ACM_NULL_POLICY:
+           printf("NULL Policy: No statistics apply.\n");
+           break;
+    case ACM_CHINESE_WALL_POLICY:
+           printf("Chinese Wall Policy: No statistics apply.\n");
+           break;
+    case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+           dump_ste_stats((struct acm_ste_stats_buffer *)(stats_buffer + ntohs(stats->primary_stats_offset)));
+           break;
+    default:
+           printf("UNKNOWN PRIMARY POLICY ERROR!\n");
+    }
+    switch(ntohs(stats->secondary_policy_code)) {
+    case ACM_NULL_POLICY:
+           printf("NULL Policy: No statistics apply.\n");
+           break;
+    case ACM_CHINESE_WALL_POLICY:
+           printf("Chinese Wall Policy: No statistics apply.\n");
+           break;
+    case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+           dump_ste_stats((struct acm_ste_stats_buffer *)(stats_buffer + ntohs(stats->secondary_stats_offset)));
+           break;
+    default:
+           printf("UNKNOWN SECONDARY POLICY ERROR!\n");
+    }                
+    return ret;
+}
+
+/***************************** main **************************************/
+
+void
+usage(char *progname){
+       printf("Use: %s \n"
+              "\t setpolicy\n"
+              "\t getpolicy\n"
+              "\t dumpstats\n"
+              "\t loadpolicy <binary policy file>\n", progname);
+       exit(-1);
+}
+
+int
+main(int argc, char **argv) {
+
+       int policycmd_fd;
+
+       if (argc < 2)
+               usage(argv[0]);
+               
+       if ((policycmd_fd = open("/proc/xen/privcmd", O_RDONLY)) <= 0) {
+                   printf("ERROR: Could not open xen policycmd device!\n");
+                   exit(-1);
+       }
+           
+       if (!strcmp(argv[1], "setpolicy")) {
+               if (argc != 2)
+                       usage(argv[0]);
+               acm_domain_setpolicy(policycmd_fd);
+
+       } else if (!strcmp(argv[1], "getpolicy")) {
+               if (argc != 2)
+                       usage(argv[0]);
+               acm_domain_getpolicy(policycmd_fd);
+
+       } else if (!strcmp(argv[1], "loadpolicy")) {
+               if (argc != 3) 
+                       usage(argv[0]);
+               acm_domain_loadpolicy(policycmd_fd, argv[2]);
+
+       } else if (!strcmp(argv[1], "dumpstats")) {
+               if (argc != 2) 
+                       usage(argv[0]);
+               acm_domain_dumpstats(policycmd_fd);
+
+       } else
+               usage(argv[0]);
+
+       close(policycmd_fd);
+       return 0;
+}
index 13d60be08e0802d83eebd9b1a0f576b24819eec1..81721d961ec1098b793fe0cb11babaa2f884e9db 100644 (file)
@@ -78,13 +78,14 @@ static PyObject *pyxc_domain_create(PyObject *self,
 
     u32          dom = 0;
     int          ret;
+    u32          ssidref = 0xFFFFFFFF;
 
-    static char *kwd_list[] = { "dom", NULL };
+    static char *kwd_list[] = { "dom", "ssidref", NULL };
 
-    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &dom))
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, &dom, &ssidref))
         return NULL;
 
-    if ( (ret = xc_domain_create(xc->xc_handle, &dom)) < 0 )
+    if ( (ret = xc_domain_create(xc->xc_handle, ssidref, &dom)) < 0 )
         return PyErr_SetFromErrno(xc_error);
 
     return PyInt_FromLong(dom);
@@ -230,7 +231,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
         }
                  
         info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
-                                  ",s:l,s:L,s:l,s:i}",
+                                  ",s:l,s:L,s:l,s:i,s:i}",
                                   "dom",       info[i].domid,
                                   "vcpus",     info[i].vcpus,
                                   "dying",     info[i].dying,
@@ -242,6 +243,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
                                   "mem_kb",    info[i].nr_pages*4,
                                   "cpu_time",  info[i].cpu_time,
                                   "maxmem_kb", info[i].max_memkb,
+                                  "ssidref",   info[i].ssidref,
                                   "shutdown_reason", info[i].shutdown_reason);
         PyDict_SetItemString( info_dict, "vcpu_to_cpu", vcpu_list );
         PyDict_SetItemString( info_dict, "cpumap", cpumap_list );
index a47709a369cb8425019f838f266273adb7be5962..0383b9c9812972cb428174c0679e0880a8b7ebdf 100644 (file)
@@ -202,7 +202,9 @@ class XendDomainInfo:
         """
         db = parentdb.addChild(uuid)
         vm = cls(db)
-        id = xc.domain_create()
+        ssidref = int(sxp.child_value(config, 'ssidref'))
+        log.debug('restoring with ssidref='+str(ssidref))
+        id = xc.domain_create(ssidref = ssidref)
         vm.setdom(id)
         try:
             vm.restore = True
@@ -241,6 +243,7 @@ class XendDomainInfo:
         self.start_time = None
         self.name = None
         self.memory = None
+        self.ssidref = None
         self.image = None
 
         self.channel = None
@@ -316,6 +319,7 @@ class XendDomainInfo:
         """
         self.info = info
         self.memory = self.info['mem_kb'] / 1024
+        self.ssidref = self.info['ssidref']
 
     def state_set(self, state):
         self.state_updated.acquire()
@@ -336,6 +340,7 @@ class XendDomainInfo:
         s += " id=" + str(self.id)
         s += " name=" + self.name
         s += " memory=" + str(self.memory)
+        s += " ssidref=" + str(self.ssidref)
         console = self.getConsole()
         if console:
             s += " console=" + str(console.console_port)
@@ -398,7 +403,8 @@ class XendDomainInfo:
         sxpr = ['domain',
                 ['id', self.id],
                 ['name', self.name],
-                ['memory', self.memory] ]
+                ['memory', self.memory],
+                ['ssidref', self.ssidref] ]
         if self.uuid:
             sxpr.append(['uuid', self.uuid])
         if self.info:
@@ -533,6 +539,7 @@ class XendDomainInfo:
         self.memory = int(sxp.child_value(config, 'memory'))
         if self.memory is None:
             raise VmError('missing memory size')
+        self.ssidref = int(sxp.child_value(config, 'ssidref'))
         cpu = sxp.child_value(config, 'cpu')
         if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
             xc.domain_pincpu(self.id, 0, 1<<int(cpu))
@@ -644,7 +651,7 @@ class XendDomainInfo:
     def show(self):
         """Print virtual machine info.
         """
-        print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory)
+        print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.id, self.name, self.memory, self.ssidref)
         print "image:"
         sxp.show(self.image)
         print "]"
@@ -660,7 +667,7 @@ class XendDomainInfo:
             cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
         except:
             raise VmError('invalid cpu')
-        id = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
+        id = self.image.initDomain(self.id, self.memory, self.ssidref, cpu, self.cpu_weight)
         log.debug('init_domain> Created domain=%d name=%s memory=%d',
                   id, self.name, self.memory)
         self.setdom(id)
@@ -1011,6 +1018,7 @@ addImageHandlerClass(VmxImageHandler)
 # Ignore the fields we already handle.
 add_config_handler('name',       vm_field_ignore)
 add_config_handler('memory',     vm_field_ignore)
+add_config_handler('ssidref',    vm_field_ignore)
 add_config_handler('cpu',        vm_field_ignore)
 add_config_handler('cpu_weight', vm_field_ignore)
 add_config_handler('console',    vm_field_ignore)
index f3b8642a5f29107f5b0d862daceb46a78644c7cb..5abc121e86214e33091a0d0adf626de72d32a987 100644 (file)
@@ -111,7 +111,7 @@ class ImageHandler:
         except OSError, ex:
             log.warning("error removing bootloader file '%s': %s", f, ex)
 
-    def initDomain(self, dom, memory, cpu, cpu_weight):
+    def initDomain(self, dom, memory, ssidref, cpu, cpu_weight):
         """Initial domain create.
 
         @return domain id
@@ -119,14 +119,14 @@ class ImageHandler:
 
         mem_kb = self.getDomainMemory(memory)
         if not self.vm.restore:
-            dom = xc.domain_create(dom = dom or 0)
+            dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
             # if bootloader, unlink here. But should go after buildDomain() ?
             if self.vm.bootloader:
                 self.unlink(self.kernel)
                 self.unlink(self.ramdisk)
             if dom <= 0:
                 raise VmError('Creating domain failed: name=%s' % self.vm.name)
-        log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom)
+        log.debug("initDomain: cpu=%d mem_kb=%d ssidref=%d dom=%d", cpu, mem_kb, ssidref, dom)
         # xc.domain_setuuid(dom, uuid)
         xc.domain_setcpuweight(dom, cpu_weight)
         xc.domain_setmaxmem(dom, mem_kb)
index d6f6291716af2350222615680010d2fa10af5e3d..7fcc7c5cf75f24b622d59def609bfb66cf3a36fe 100644 (file)
@@ -142,6 +142,7 @@ class SrvDomainDir(SrvDir):
                          % (url, d.name, d.name))
                req.write('id=%s' % d.id)
                req.write('memory=%d'% d.memory)
+               req.write('ssidref=%d'% d.ssidref)
                req.write('</li>')
             req.write('</ul>')
 
index 23001cc45859b87ebf498fc7d364bc423778621b..d2219f9668e949a20a442b5ba83751f688b1e620 100644 (file)
@@ -120,6 +120,10 @@ gopts.var('memory', val='MEMORY',
           fn=set_int, default=128,
           use="Domain memory in MB.")
 
+gopts.var('ssidref', val='SSIDREF',
+          fn=set_u32, default=0xffffffff,
+          use="Security Identifier.")
+
 gopts.var('maxmem', val='MEMORY',
           fn=set_int, default=None,
           use="Maximum domain memory in MB.")
@@ -405,7 +409,8 @@ def make_config(opts, vals):
     
     config = ['vm',
               ['name', vals.name ],
-              ['memory', vals.memory ]]
+              ['memory', vals.memory ],
+              ['ssidref', vals.ssidref ]]
     if vals.maxmem:
         config.append(['maxmem', vals.maxmem])
     if vals.cpu is not None:
index d02a190ac4a0003f38828aab920c262310cf790b..6eda17e2a97f16ca276bf02046a9fdf2d80e4671 100644 (file)
@@ -383,7 +383,7 @@ class ProgList(Prog):
             self.brief_list(doms)
 
     def brief_list(self, doms):
-        print 'Name              Id  Mem(MB)  CPU VCPU(s)  State  Time(s)  Console'
+        print 'Name              Id  Mem(MB)  CPU VCPU(s)  State  Time(s)  Console  SSID-REF'
         for dom in doms:
             info = server.xend_domain(dom)
             d = {}
@@ -399,8 +399,12 @@ class ProgList(Prog):
                 d['port'] = sxp.child_value(console, 'console_port')
             else:
                 d['port'] = ''
-            print ("%(name)-16s %(dom)3d  %(mem)7d  %(cpu)3d  %(vcpus)5d   %(state)5s  %(cpu_time)7.1f     %(port)4s"
-                   % d)
+            if ((int(sxp.child_value(info, 'ssidref', '-1'))) != -1):
+                d['ssidref1'] =  int(sxp.child_value(info, 'ssidref', '-1')) & 0xffff
+                d['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '-1')) >> 16) & 0xffff
+                print ("%(name)-16s %(dom)3d  %(mem)7d  %(cpu)3d  %(vcpus)5d   %(state)5s  %(cpu_time)7.1f     %(port)4s    s:%(ssidref2)02x/p:%(ssidref1)02x" % d)
+            else:
+                print ("%(name)-16s %(dom)3d  %(mem)7d  %(cpu)3d  %(vcpus)5d   %(state)5s  %(cpu_time)7.1f     %(port)4s     default" % d)
 
     def show_vcpus(self, doms):
         print 'Name              Id  VCPU  CPU  CPUMAP'
index f92c82dfe6984f490dda1814dc16b4e3a40d490c..30900450dc6928a00ce084d907b8f085f93828fe 100644 (file)
@@ -451,6 +451,13 @@ def set_bool(opt, k, v):
     else:
         opt.opts.err('Invalid value:' +v)
         
+def set_u32(opt, k, v):
+    """Set an option to an u32 value."""
+    try:
+        v = u32(v)
+    except:
+        opt.opts.err('Invalid value: ' + str(v))
+    opt.set(v)
 
 def set_value(opt, k, v):
     """Set an option to a value."""
index e71898cf4d37204475ade4e07ac558453f9a208b..15b55fb24d93d50a5e03c203d4c8e96e7c919efc 100644 (file)
@@ -46,6 +46,7 @@ clean: delete-unfresh-files
        $(MAKE) -C tools clean
        $(MAKE) -C common clean
        $(MAKE) -C drivers clean
+       $(MAKE) -C acm clean
        $(MAKE) -C arch/$(TARGET_ARCH) clean
        rm -f include/asm *.o $(TARGET)* *~ core
        rm -f include/asm-*/asm-offsets.h
@@ -58,6 +59,7 @@ $(TARGET): delete-unfresh-files
        $(MAKE) include/asm-$(TARGET_ARCH)/asm-offsets.h
        $(MAKE) -C common
        $(MAKE) -C drivers
+       $(MAKE) -C acm
        $(MAKE) -C arch/$(TARGET_ARCH)
 
 # drivers/char/console.o may contain static banner/compile info. Blow it away.
@@ -109,7 +111,7 @@ include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s
 
 .PHONY: default debug install dist clean delete-unfresh-files TAGS tags
 
-SUBDIRS = arch/$(TARGET_ARCH) common drivers 
+SUBDIRS = acm arch/$(TARGET_ARCH) common drivers 
 define all_sources
     ( find include/asm-$(TARGET_ARCH) -name SCCS -prune -o -name '*.h' -print; \
       find include -type d -name SCCS -prune -o \( -name "asm-*" -o \
index 221882814a633ede954d696776be487898404fe5..c0b13ae368405a3e9bc500597a0faaa1a48ed6e7 100644 (file)
@@ -35,6 +35,7 @@ OBJS    += $(patsubst %.c,%.o,$(C_SRCS))
 ALL_OBJS := $(BASEDIR)/common/common.o
 ALL_OBJS += $(BASEDIR)/drivers/char/driver.o
 ALL_OBJS += $(BASEDIR)/drivers/acpi/driver.o
+ALL_OBJS += $(BASEDIR)/acm/acm.o
 ALL_OBJS += $(BASEDIR)/arch/$(TARGET_ARCH)/arch.o
 
 
diff --git a/xen/acm/Makefile b/xen/acm/Makefile
new file mode 100644 (file)
index 0000000..b212041
--- /dev/null
@@ -0,0 +1,15 @@
+
+include $(BASEDIR)/Rules.mk
+OBJS =  acm_core.o 
+OBJS += acm_policy.o
+OBJS += acm_simple_type_enforcement_hooks.o
+OBJS += acm_chinesewall_hooks.o
+OBJS += acm_null_hooks.o
+
+default: acm.o
+
+acm.o: $(OBJS)
+       $(LD) $(LDFLAGS) -r -o acm.o $(OBJS)
+
+clean:
+       rm -f *.o *~ core
diff --git a/xen/acm/acm_chinesewall_hooks.c b/xen/acm/acm_chinesewall_hooks.c
new file mode 100644 (file)
index 0000000..938716d
--- /dev/null
@@ -0,0 +1,503 @@
+/****************************************************************
+ * acm_chinesewall_hooks.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype Chinese Wall Policy for Xen
+ *    This code implements the hooks that are called
+ *    throughout Xen operations and decides authorization
+ *    based on domain types and Chinese Wall conflict type 
+ *    sets. The CHWALL policy decides if a new domain can be started
+ *    based on the types of running domains and the type of the
+ *    new domain to be started. If the new domain's type is in
+ *    conflict with types of running domains, then this new domain
+ *    is not allowed to be created. A domain can have multiple types,
+ *    in which case all types of a new domain must be conflict-free
+ *    with all types of already running domains.
+ *
+ */
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/acm.h>
+#include <asm/atomic.h>
+#include <acm/acm_core.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+/* local cache structures for chinese wall policy */
+struct chwall_binary_policy chwall_bin_pol;
+
+/*
+ * Initializing chinese wall policy (will be filled by policy partition
+ * using setpolicy command)
+ */
+int acm_init_chwall_policy(void)
+{
+       /* minimal startup policy; policy write-locked already */
+       chwall_bin_pol.max_types = 1;
+       chwall_bin_pol.max_ssidrefs = 1;
+       chwall_bin_pol.max_conflictsets = 1;
+       chwall_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types);
+       chwall_bin_pol.conflict_sets = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types);
+       chwall_bin_pol.running_types = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
+       chwall_bin_pol.conflict_aggregate_set = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
+       
+       if ((chwall_bin_pol.conflict_sets == NULL) || (chwall_bin_pol.running_types == NULL) ||
+           (chwall_bin_pol.ssidrefs == NULL) || (chwall_bin_pol.conflict_aggregate_set == NULL))
+               return ACM_INIT_SSID_ERROR;
+
+       /* initialize state */
+       memset((void *)chwall_bin_pol.ssidrefs, 0, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types*sizeof(domaintype_t));
+       memset((void *)chwall_bin_pol.conflict_sets, 0, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types*sizeof(domaintype_t));
+       memset((void *)chwall_bin_pol.running_types, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
+       memset((void *)chwall_bin_pol.conflict_aggregate_set, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));        
+       return ACM_OK;
+}
+
+static int
+chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
+{
+       struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
+       traceprintk("%s.\n", __func__);
+       if (chwall_ssidp == NULL)
+               return ACM_INIT_SSID_ERROR;
+       /* 
+        * depending on wheter chwall is primary or secondary, get the respective
+        * part of the global ssidref (same way we'll get the partial ssid pointer)
+        */
+       chwall_ssidp->chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+       if (chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
+               printkd("%s: ERROR chwall_ssidref(%x) > max(%x).\n",
+                       __func__, chwall_ssidp->chwall_ssidref, chwall_bin_pol.max_ssidrefs-1);
+               xfree(chwall_ssidp);
+               return ACM_INIT_SSID_ERROR;
+       }
+       (*chwall_ssid) = chwall_ssidp;
+       printkd("%s: determined chwall_ssidref to %x.\n", 
+              __func__, chwall_ssidp->chwall_ssidref);
+       return ACM_OK;
+}
+
+static void
+chwall_free_domain_ssid(void *chwall_ssid)
+{
+       traceprintk("%s.\n", __func__);
+       if (chwall_ssid != NULL)
+               xfree(chwall_ssid);
+       return;
+}
+
+
+/* dump chinese wall cache; policy read-locked already */
+static int
+chwall_dump_policy(u8 *buf, u16 buf_size) {    
+     struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
+     int ret = 0;
+
+     chwall_buf->chwall_max_types = htons(chwall_bin_pol.max_types);
+     chwall_buf->chwall_max_ssidrefs = htons(chwall_bin_pol.max_ssidrefs);
+     chwall_buf->policy_code = htons(ACM_CHINESE_WALL_POLICY);
+     chwall_buf->chwall_ssid_offset = htons(sizeof(struct acm_chwall_policy_buffer));
+     chwall_buf->chwall_max_conflictsets = htons(chwall_bin_pol.max_conflictsets);
+     chwall_buf->chwall_conflict_sets_offset =
+            htons(
+                  ntohs(chwall_buf->chwall_ssid_offset) + 
+                  sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs * 
+                  chwall_bin_pol.max_types);
+
+     chwall_buf->chwall_running_types_offset = 
+            htons(
+                  ntohs(chwall_buf->chwall_conflict_sets_offset) +
+                  sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets *
+                  chwall_bin_pol.max_types);
+
+     chwall_buf->chwall_conflict_aggregate_offset =
+            htons(
+                  ntohs(chwall_buf->chwall_running_types_offset) +
+                  sizeof(domaintype_t) * chwall_bin_pol.max_types);
+
+     ret = ntohs(chwall_buf->chwall_conflict_aggregate_offset) +
+            sizeof(domaintype_t) * chwall_bin_pol.max_types;
+
+     /* now copy buffers over */
+     arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_ssid_offset)),
+             chwall_bin_pol.ssidrefs,
+             chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types);
+
+     arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_conflict_sets_offset)),
+             chwall_bin_pol.conflict_sets,
+             chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types);
+
+     arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_running_types_offset)),
+             chwall_bin_pol.running_types,
+             chwall_bin_pol.max_types);
+
+     arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_conflict_aggregate_offset)),
+             chwall_bin_pol.conflict_aggregate_set,
+             chwall_bin_pol.max_types);
+     return ret;
+}
+
+/* adapt security state (running_types and conflict_aggregate_set) to all running
+ * domains; chwall_init_state is called when a policy is changed to bring the security
+ * information into a consistent state and to detect violations (return != 0).
+ * from a security point of view, we simulate that all running domains are re-started
+ */ 
+static int
+chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, domaintype_t *ssidrefs, domaintype_t *conflict_sets,
+                 domaintype_t *running_types, domaintype_t *conflict_aggregate_set)
+{
+       int violation = 0, i, j;
+       struct chwall_ssid *chwall_ssid;
+       ssidref_t chwall_ssidref;
+       struct domain **pd;
+
+        write_lock(&domlist_lock);
+       /* go through all domains and adjust policy as if this domain was started now */
+        pd = &domain_list;
+        for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+               chwall_ssid = GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)(*pd)->ssid);
+               chwall_ssidref = chwall_ssid->chwall_ssidref;
+               traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n", 
+                       __func__, (*pd)->domain_id, chwall_ssidref);
+               /* a) adjust types ref-count for running domains */
+               for (i=0; i< chwall_buf->chwall_max_types; i++)
+                       running_types[i] +=
+                               ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i];
+
+               /* b) check for conflict */
+               for (i=0; i< chwall_buf->chwall_max_types; i++)
+                       if (conflict_aggregate_set[i] && 
+                           ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i]) {
+                               printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
+                               violation = 1;
+                               goto out;
+                       }
+               /* set violation and break out of the loop */
+               /* c) adapt conflict aggregate set for this domain (notice conflicts) */
+               for (i=0; i<chwall_buf->chwall_max_conflictsets; i++) {
+                       int common = 0;
+                       /* check if conflict_set_i and ssidref have common types */
+                       for (j=0; j<chwall_buf->chwall_max_types; j++)
+                               if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
+                                   ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j]) {
+                                       common = 1;
+                                       break;
+                               }
+                       if (common == 0)
+                               continue; /* try next conflict set */
+                       /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+                       for (j=0; j<chwall_buf->chwall_max_types; j++)
+                               if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
+                                   !ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j])
+                                       conflict_aggregate_set[j]++;
+               }       
+       }
+ out:
+        write_unlock(&domlist_lock);
+       return violation;
+       /* returning "violation != 0" means that the currently running set of domains would 
+        * not be possible if the new policy had been enforced before starting them; for chinese
+        * wall, this means that the new policy includes at least one conflict set of which 
+        * more than one type is currently running */
+}
+
+static int
+chwall_set_policy(u8 *buf, u16 buf_size) 
+{      
+       /* policy write-locked already */
+       struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
+       void *ssids = NULL, *conflict_sets = NULL, *running_types = NULL, *conflict_aggregate_set = NULL;       
+
+        /* rewrite the policy due to endianess */
+        chwall_buf->policy_code                      = ntohs(chwall_buf->policy_code);
+        chwall_buf->chwall_max_types                 = ntohs(chwall_buf->chwall_max_types);
+        chwall_buf->chwall_max_ssidrefs              = ntohs(chwall_buf->chwall_max_ssidrefs);
+        chwall_buf->chwall_max_conflictsets          = ntohs(chwall_buf->chwall_max_conflictsets);
+        chwall_buf->chwall_ssid_offset               = ntohs(chwall_buf->chwall_ssid_offset);
+        chwall_buf->chwall_conflict_sets_offset      = ntohs(chwall_buf->chwall_conflict_sets_offset);
+        chwall_buf->chwall_running_types_offset      = ntohs(chwall_buf->chwall_running_types_offset);
+        chwall_buf->chwall_conflict_aggregate_offset = ntohs(chwall_buf->chwall_conflict_aggregate_offset);
+
+       /* 1. allocate new buffers */
+       ssids = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types*chwall_buf->chwall_max_ssidrefs);
+       conflict_sets = xmalloc_array(domaintype_t, chwall_buf->chwall_max_conflictsets*chwall_buf->chwall_max_types);
+       running_types = xmalloc_array(domaintype_t,chwall_buf->chwall_max_types);
+       conflict_aggregate_set = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
+
+       if ((ssids == NULL)||(conflict_sets == NULL)||(running_types == NULL)||(conflict_aggregate_set == NULL))
+               goto error_free;
+
+       /* 2. set new policy */
+       if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) * 
+           chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs > buf_size)
+               goto error_free;
+       arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset,
+              sizeof(domaintype_t),  
+              chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs);
+
+       if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) * 
+           chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets > buf_size)
+               goto error_free;
+
+       arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset,
+              sizeof(domaintype_t),
+              chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets);
+
+       /* we also use new state buffers since max_types can change */
+       memset(running_types, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
+       memset(conflict_aggregate_set, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
+
+       /* 3. now re-calculate the state for the new policy based on running domains; 
+        *    this can fail if new policy is conflicting with running domains */
+       if (chwall_init_state(chwall_buf, ssids, conflict_sets, running_types, conflict_aggregate_set)) {
+               printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
+               goto error_free; /* new policy conflicts with running domains */
+       }
+       /* 4. free old policy buffers, replace with new ones */
+       chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
+       chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
+       chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets;
+       if (chwall_bin_pol.ssidrefs != NULL) 
+               xfree(chwall_bin_pol.ssidrefs);
+       if (chwall_bin_pol.conflict_aggregate_set != NULL) 
+               xfree(chwall_bin_pol.conflict_aggregate_set);
+       if (chwall_bin_pol.running_types != NULL) 
+               xfree(chwall_bin_pol.running_types);
+       if (chwall_bin_pol.conflict_sets != NULL) 
+               xfree(chwall_bin_pol.conflict_sets);
+       chwall_bin_pol.ssidrefs = ssids;
+       chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set;
+       chwall_bin_pol.running_types = running_types;
+       chwall_bin_pol.conflict_sets = conflict_sets;
+       return ACM_OK;
+
+error_free:
+       printk("%s: ERROR setting policy.\n", __func__);
+       if (ssids != NULL) xfree(ssids);
+       if (conflict_sets != NULL) xfree(conflict_sets);
+       if (running_types != NULL) xfree(running_types);
+       if (conflict_aggregate_set != NULL) xfree(conflict_aggregate_set);
+       return -EFAULT;
+}
+       
+static int 
+chwall_dump_stats(u8 *buf, u16 len)
+{
+       /* no stats for Chinese Wall Policy */
+       return 0;
+}
+
+/***************************
+ * Authorization functions
+ ***************************/
+
+
+/* -------- DOMAIN OPERATION HOOKS -----------*/
+
+static int 
+chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+       ssidref_t chwall_ssidref;
+       int i,j;
+       traceprintk("%s.\n", __func__);
+
+       read_lock(&acm_bin_pol_rwlock);
+       chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+       if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) {
+               printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n", __func__);
+               read_unlock(&acm_bin_pol_rwlock);
+               return ACM_ACCESS_DENIED; /* catching and indicating config error */
+       }
+       if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
+               printk("%s: ERROR chwall_ssidref > max(%x).\n",
+                      __func__, chwall_bin_pol.max_ssidrefs-1);
+               read_unlock(&acm_bin_pol_rwlock);
+               return ACM_ACCESS_DENIED;
+       }
+       /* A: chinese wall check for conflicts */
+       for (i=0; i< chwall_bin_pol.max_types; i++)
+               if (chwall_bin_pol.conflict_aggregate_set[i] && 
+                   chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i]) {
+                       printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
+                       read_unlock(&acm_bin_pol_rwlock);
+                       return ACM_ACCESS_DENIED;
+               }
+
+       /* B: chinese wall conflict set adjustment (so that other 
+        *      other domains simultaneously created are evaluated against this new set)*/
+       for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+               int common = 0;
+               /* check if conflict_set_i and ssidref have common types */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+                               common = 1;
+                               break;
+                       }
+               if (common == 0)
+                       continue; /* try next conflict set */
+               /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+                               chwall_bin_pol.conflict_aggregate_set[j]++;
+       }
+       read_unlock(&acm_bin_pol_rwlock);
+       return ACM_ACCESS_PERMITTED;
+}
+
+static void
+chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
+{
+       int i,j;
+       ssidref_t chwall_ssidref;
+       traceprintk("%s.\n", __func__);
+       
+       read_lock(&acm_bin_pol_rwlock);
+       chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+       /* adjust types ref-count for running domains */
+       for (i=0; i< chwall_bin_pol.max_types; i++)
+               chwall_bin_pol.running_types[i] +=
+                       chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
+       if (domid) {
+               read_unlock(&acm_bin_pol_rwlock);
+               return;
+       }
+       /* Xen does not call pre-create hook for DOM0;
+        * to consider type conflicts of any domain with DOM0, we need
+        * to adjust the conflict_aggregate for DOM0 here the same way it
+        * is done for non-DOM0 domains in the pre-hook */
+       printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n", 
+               __func__, ssidref, chwall_ssidref);
+
+       /* chinese wall conflict set adjustment (so that other 
+        *      other domains simultaneously created are evaluated against this new set)*/
+       for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+               int common = 0;
+               /* check if conflict_set_i and ssidref have common types */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+                               common = 1;
+                               break;
+                       }
+               if (common == 0)
+                       continue; /* try next conflict set */
+               /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+                               chwall_bin_pol.conflict_aggregate_set[j]++;
+       }
+       read_unlock(&acm_bin_pol_rwlock);
+       return;
+}
+
+static void
+chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+       int i, j;
+       ssidref_t chwall_ssidref;
+       traceprintk("%s.\n", __func__);
+
+       read_lock(&acm_bin_pol_rwlock);
+       chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+       /* roll-back: re-adjust conflicting types aggregate */
+       for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+               int common = 0;
+               /* check if conflict_set_i and ssidref have common types */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+                               common = 1;
+                               break;
+                       }
+               if (common == 0)
+                       continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
+               /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+                               chwall_bin_pol.conflict_aggregate_set[j]--;
+       }
+       read_unlock(&acm_bin_pol_rwlock);
+}
+
+
+static void
+chwall_post_domain_destroy(void *object_ssid, domid_t id) 
+{
+       int i,j;
+       struct chwall_ssid *chwall_ssidp = 
+               GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)object_ssid);
+       ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref;
+
+       traceprintk("%s.\n", __func__);
+
+       read_lock(&acm_bin_pol_rwlock);
+       /* adjust running types set */
+       for (i=0; i< chwall_bin_pol.max_types; i++)
+               chwall_bin_pol.running_types[i] -=
+                       chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
+
+       /* roll-back: re-adjust conflicting types aggregate */
+       for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+               int common = 0;
+               /* check if conflict_set_i and ssidref have common types */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+                               common = 1;
+                               break;
+                       }
+               if (common == 0)
+                       continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
+               /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+               for (j=0; j<chwall_bin_pol.max_types; j++)
+                       if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+                           !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+                               chwall_bin_pol.conflict_aggregate_set[j]--;
+       }
+       read_unlock(&acm_bin_pol_rwlock);
+       return;
+}
+
+struct acm_operations acm_chinesewall_ops = {
+       /* policy management services */
+       .init_domain_ssid               = chwall_init_domain_ssid,
+       .free_domain_ssid               = chwall_free_domain_ssid,
+       .dump_binary_policy             = chwall_dump_policy,
+       .set_binary_policy              = chwall_set_policy,
+       .dump_statistics                = chwall_dump_stats,
+       /* domain management control hooks */
+       .pre_domain_create              = chwall_pre_domain_create,
+       .post_domain_create             = chwall_post_domain_create,
+       .fail_domain_create             = chwall_fail_domain_create,
+       .post_domain_destroy            = chwall_post_domain_destroy,
+       /* event channel control hooks */
+       .pre_eventchannel_unbound       = NULL,
+       .fail_eventchannel_unbound      = NULL,
+       .pre_eventchannel_interdomain   = NULL,
+       .fail_eventchannel_interdomain  = NULL,
+       /* grant table control hooks */
+       .pre_grant_map_ref              = NULL,
+       .fail_grant_map_ref             = NULL,
+       .pre_grant_setup                = NULL,
+       .fail_grant_setup               = NULL,
+};
diff --git a/xen/acm/acm_core.c b/xen/acm/acm_core.c
new file mode 100644 (file)
index 0000000..fe5bacd
--- /dev/null
@@ -0,0 +1,205 @@
+/****************************************************************
+ * acm_core.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype access control module (ACM)
+ *       This file handles initialization of the ACM
+ *       as well as initializing/freeing security 
+ *       identifiers for domains (it calls on active
+ *       policy hook functions).
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+/* debug: 
+ *   include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE;
+ *   define/undefine this constant to receive / suppress any
+ *   security hook debug output of sHype
+ *
+ *   include/public/acm.h defines a constant ACM_DEBUG
+ *   define/undefine this constant to receive non-hook-related
+ *   debug output.
+ */
+
+/* function prototypes */
+void acm_init_chwall_policy(void);
+void acm_init_ste_policy(void);
+
+extern struct acm_operations acm_chinesewall_ops, 
+       acm_simple_type_enforcement_ops, acm_null_ops;
+
+/* global ops structs called by the hooks */
+struct acm_operations *acm_primary_ops = NULL;
+/* called in hook if-and-only-if primary succeeds */
+struct acm_operations *acm_secondary_ops = NULL;
+
+/* acm global binary policy (points to 'local' primary and secondary policies */
+struct acm_binary_policy acm_bin_pol;
+/* acm binary policy lock */
+rwlock_t acm_bin_pol_rwlock = RW_LOCK_UNLOCKED;
+
+/* until we have endian support in Xen, we discover it at runtime */
+u8 little_endian = 1;
+void acm_set_endian(void)
+{
+    u32 test = 1;
+    if (*((u8 *)&test) == 1) {
+       printk("ACM module running in LITTLE ENDIAN.\n");
+       little_endian = 1;
+    } else {
+       printk("ACM module running in BIG ENDIAN.\n");
+       little_endian = 0;
+    }
+}
+
+/* initialize global security policy for Xen; policy write-locked already */
+static void
+acm_init_binary_policy(void *primary, void *secondary)
+{
+       acm_bin_pol.primary_policy_code = 0;
+       acm_bin_pol.secondary_policy_code = 0;
+       acm_bin_pol.primary_binary_policy = primary;
+       acm_bin_pol.secondary_binary_policy = secondary;
+}
+
+int
+acm_init(void)
+{
+       int ret = -EINVAL;
+
+       acm_set_endian();
+       write_lock(&acm_bin_pol_rwlock);
+
+       if (ACM_USE_SECURITY_POLICY == ACM_CHINESE_WALL_POLICY) {
+               acm_init_binary_policy(NULL, NULL);
+               acm_init_chwall_policy();
+               acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
+               acm_primary_ops = &acm_chinesewall_ops;
+               acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+               acm_secondary_ops = &acm_null_ops;
+               ret = ACM_OK;
+       } else if (ACM_USE_SECURITY_POLICY == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+               acm_init_binary_policy(NULL, NULL);
+               acm_init_ste_policy();
+               acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+               acm_primary_ops = &acm_simple_type_enforcement_ops;
+               acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+               acm_secondary_ops = &acm_null_ops;
+               ret = ACM_OK;
+       } else if (ACM_USE_SECURITY_POLICY == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+               acm_init_binary_policy(NULL, NULL);
+               acm_init_chwall_policy();
+               acm_init_ste_policy();
+               acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
+               acm_primary_ops = &acm_chinesewall_ops;
+               acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+               acm_secondary_ops = &acm_simple_type_enforcement_ops;
+               ret = ACM_OK;
+       } else if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) {
+               acm_init_binary_policy(NULL, NULL);
+               acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
+               acm_primary_ops = &acm_null_ops;
+               acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+               acm_secondary_ops = &acm_null_ops;
+               ret = ACM_OK;
+       }
+       write_unlock(&acm_bin_pol_rwlock);
+
+       if (ret != ACM_OK)
+               return -EINVAL;         
+       printk("%s: Enforcing Primary %s, Secondary %s.\n", __func__, 
+              ACM_POLICY_NAME(acm_bin_pol.primary_policy_code), ACM_POLICY_NAME(acm_bin_pol.secondary_policy_code));
+       return ACM_OK;
+}
+
+
+int
+acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
+{
+       struct acm_ssid_domain *ssid;
+       struct domain *subj = find_domain_by_id(id);
+       int ret1, ret2;
+       
+       if (subj == NULL) {
+               printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
+               return ACM_NULL_POINTER_ERROR;
+       }
+       if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
+               return ACM_INIT_SSID_ERROR;
+
+       ssid->datatype       = DOMAIN;
+       ssid->subject        = subj;
+       ssid->domainid       = subj->domain_id;
+       ssid->primary_ssid   = NULL;
+       ssid->secondary_ssid = NULL;
+
+       if (ACM_USE_SECURITY_POLICY != ACM_NULL_POLICY)
+               ssid->ssidref = ssidref;
+       else
+               ssid->ssidref = ACM_DEFAULT_SSID;
+
+       subj->ssid           = ssid;
+       /* now fill in primary and secondary parts; we only get here through hooks */
+       if (acm_primary_ops->init_domain_ssid != NULL)
+               ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
+       else
+               ret1 = ACM_OK;
+
+       if (acm_secondary_ops->init_domain_ssid != NULL)
+               ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
+       else
+               ret2 = ACM_OK;
+
+       if ((ret1 != ACM_OK) || (ret2 != ACM_OK)) {
+               printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
+                      __func__, subj->domain_id);
+               acm_free_domain_ssid(ssid);     
+               put_domain(subj);
+               return ACM_INIT_SSID_ERROR;
+       }
+       printk("%s: assigned domain %x the ssidref=%x.\n", __func__, id, ssid->ssidref);
+       put_domain(subj);
+       return ACM_OK;
+}
+
+
+int
+acm_free_domain_ssid(struct acm_ssid_domain *ssid)
+{
+       domid_t id;
+
+       /* domain is already gone, just ssid is left */
+       if (ssid == NULL) {
+               printk("%s: ACM_NULL_POINTER ERROR.\n", __func__);
+               return ACM_NULL_POINTER_ERROR;
+       }
+               id = ssid->domainid;
+       ssid->subject        = NULL;
+
+       if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
+               acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
+       ssid->primary_ssid = NULL;
+       if (acm_secondary_ops->free_domain_ssid != NULL)
+               acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
+       ssid->secondary_ssid = NULL;
+       xfree(ssid);
+       printkd("%s: Freed individual domain ssid (domain=%02x).\n",__func__, id);
+       return ACM_OK;
+}
diff --git a/xen/acm/acm_null_hooks.c b/xen/acm/acm_null_hooks.c
new file mode 100644 (file)
index 0000000..6433cbf
--- /dev/null
@@ -0,0 +1,76 @@
+/****************************************************************
+ * acm_null_hooks.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+#include <acm/acm_hooks.h>
+
+static int
+null_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
+{
+       return ACM_OK;
+}
+
+
+static void
+null_free_domain_ssid(void *chwall_ssid)
+{
+       return;
+}
+
+
+static int
+null_dump_binary_policy(u8 *buf, u16 buf_size) 
+{      
+       return 0;
+}
+
+
+
+static int
+null_set_binary_policy(u8 *buf, u16 buf_size) 
+{      
+       return -1;
+}
+
+       
+static int 
+null_dump_stats(u8 *buf, u16 buf_size)
+{
+       /* no stats for NULL policy */
+       return 0;
+}
+
+
+/* now define the hook structure similarly to LSM */
+struct acm_operations acm_null_ops = {
+       .init_domain_ssid               = null_init_domain_ssid,
+       .free_domain_ssid               = null_free_domain_ssid,
+       .dump_binary_policy             = null_dump_binary_policy,
+       .set_binary_policy              = null_set_binary_policy,
+       .dump_statistics                = null_dump_stats,
+       /* domain management control hooks */
+       .pre_domain_create              = NULL,
+       .post_domain_create             = NULL,
+       .fail_domain_create             = NULL,
+       .post_domain_destroy            = NULL,
+       /* event channel control hooks */
+       .pre_eventchannel_unbound       = NULL,
+       .fail_eventchannel_unbound      = NULL,
+       .pre_eventchannel_interdomain   = NULL,
+       .fail_eventchannel_interdomain  = NULL,
+       /* grant table control hooks */
+       .pre_grant_map_ref              = NULL,
+       .fail_grant_map_ref             = NULL,
+       .pre_grant_setup                = NULL,
+       .fail_grant_setup               = NULL
+
+};
diff --git a/xen/acm/acm_policy.c b/xen/acm/acm_policy.c
new file mode 100644 (file)
index 0000000..3e08130
--- /dev/null
@@ -0,0 +1,197 @@
+/****************************************************************
+ * acm_policy.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *     support for network-byte-order binary policies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype access control policy management for Xen.
+ *       This interface allows policy tools in authorized
+ *       domains to interact with the Xen access control module
+ * 
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/policy_ops.h>
+#include <acm/acm_core.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+int
+acm_set_policy(void *buf, u16 buf_size, u16 policy)
+{
+       u8 *policy_buffer = NULL;
+       struct acm_policy_buffer *pol;
+       
+       if (policy != ACM_USE_SECURITY_POLICY) {
+               printk("%s: Loading incompatible policy (running: %s).\n", __func__,
+                      ACM_POLICY_NAME(ACM_USE_SECURITY_POLICY));
+               return -EFAULT;
+       }
+       /* now check correct buffer sizes for policy combinations */
+       if (policy == ACM_NULL_POLICY) {
+               printkd("%s: NULL Policy, no policy needed.\n", __func__);
+               goto out;
+       }
+       if (buf_size < sizeof(struct acm_policy_buffer))
+               return -EFAULT;
+       /* 1. copy buffer from domain */
+       if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
+           goto error_free;
+        if (copy_from_user(policy_buffer, buf, buf_size)) {
+               printk("%s: Error copying!\n",__func__);
+               goto error_free;
+       }
+       /* 2. some sanity checking */
+       pol = (struct acm_policy_buffer *)policy_buffer;
+
+       if ((ntohl(pol->magic) != ACM_MAGIC) || 
+           (ntohs(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) ||
+           (ntohs(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code)) {
+               printkd("%s: Wrong policy magics!\n", __func__);
+               goto error_free;
+       }
+       if (buf_size != ntohl(pol->len)) {
+               printk("%s: ERROR in buf size.\n", __func__);
+               goto error_free;
+       }
+
+       /* get bin_policy lock and rewrite policy (release old one) */
+       write_lock(&acm_bin_pol_rwlock);
+
+       /* 3. now get/set primary policy data */
+       if (acm_primary_ops->set_binary_policy(buf + ntohs(pol->primary_buffer_offset), 
+                                               ntohs(pol->secondary_buffer_offset) -
+                                              ntohs(pol->primary_buffer_offset))) {
+               goto error_lock_free;
+       }
+       /* 4. now get/set secondary policy data */
+       if (acm_secondary_ops->set_binary_policy(buf + ntohs(pol->secondary_buffer_offset),
+                                                ntohl(pol->len) - 
+                                                ntohs(pol->secondary_buffer_offset))) {
+               goto error_lock_free;
+       }
+       write_unlock(&acm_bin_pol_rwlock);
+ out:
+       printk("%s: Done .\n", __func__);
+       if (policy_buffer != NULL)
+               xfree(policy_buffer);
+       return ACM_OK;
+
+ error_lock_free:
+       write_unlock(&acm_bin_pol_rwlock);
+ error_free:
+       printk("%s: Error setting policy.\n", __func__);
+       if (policy_buffer != NULL)
+               xfree(policy_buffer);
+       return -ENOMEM;
+}
+
+int
+acm_get_policy(void *buf, u16 buf_size)
+{      
+     u8 *policy_buffer;
+     int ret;
+     struct acm_policy_buffer *bin_pol;
+       
+     if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
+           return -ENOMEM;
+
+     read_lock(&acm_bin_pol_rwlock);
+     /* future: read policy from file and set it */
+     bin_pol = (struct acm_policy_buffer *)policy_buffer;
+     bin_pol->magic = htonl(ACM_MAGIC);
+     bin_pol->policyversion = htonl(POLICY_INTERFACE_VERSION);
+     bin_pol->primary_policy_code = htons(acm_bin_pol.primary_policy_code);
+     bin_pol->secondary_policy_code = htons(acm_bin_pol.secondary_policy_code);
+
+     bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
+     bin_pol->primary_buffer_offset = htons(ntohl(bin_pol->len));
+     bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+     
+     ret = acm_primary_ops->dump_binary_policy (policy_buffer + ntohs(bin_pol->primary_buffer_offset),
+                                      buf_size - ntohs(bin_pol->primary_buffer_offset));
+     if (ret < 0) {
+            printk("%s: ERROR creating chwallpolicy buffer.\n", __func__);
+            read_unlock(&acm_bin_pol_rwlock);
+            return -1;
+     }
+     bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+     bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+
+     ret = acm_secondary_ops->dump_binary_policy(policy_buffer + ntohs(bin_pol->secondary_buffer_offset), 
+                                   buf_size - ntohs(bin_pol->secondary_buffer_offset));
+     if (ret < 0) {
+            printk("%s: ERROR creating chwallpolicy buffer.\n", __func__);
+            read_unlock(&acm_bin_pol_rwlock);
+            return -1;
+     }
+     bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+     read_unlock(&acm_bin_pol_rwlock);
+     if (copy_to_user(buf, policy_buffer, ntohl(bin_pol->len)))
+            return -EFAULT;
+     xfree(policy_buffer);
+     return ACM_OK;
+}
+
+int
+acm_dump_statistics(void *buf, u16 buf_size)
+{      
+    /* send stats to user space */
+     u8 *stats_buffer;
+     int len1, len2;
+     struct acm_stats_buffer acm_stats;
+
+     if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL)
+           return -ENOMEM;
+
+     read_lock(&acm_bin_pol_rwlock);
+     
+     len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer),
+                                            buf_size - sizeof(struct acm_stats_buffer));
+     if (len1 < 0)
+            goto error_lock_free;
+            
+     len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1,
+                                              buf_size - sizeof(struct acm_stats_buffer) - len1);
+     if (len2 < 0)
+            goto error_lock_free;
+
+     acm_stats.magic = htonl(ACM_MAGIC);
+     acm_stats.policyversion = htonl(POLICY_INTERFACE_VERSION);
+     acm_stats.primary_policy_code = htons(acm_bin_pol.primary_policy_code);
+     acm_stats.secondary_policy_code = htons(acm_bin_pol.secondary_policy_code);
+     acm_stats.primary_stats_offset = htons(sizeof(struct acm_stats_buffer));
+     acm_stats.secondary_stats_offset = htons(sizeof(struct acm_stats_buffer) + len1);
+     acm_stats.len = htonl(sizeof(struct acm_stats_buffer) + len1 + len2);
+     memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
+
+     if (copy_to_user(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2))
+            goto error_lock_free;
+
+     read_unlock(&acm_bin_pol_rwlock);
+     xfree(stats_buffer);
+     return ACM_OK;
+
+ error_lock_free:
+     read_unlock(&acm_bin_pol_rwlock);
+     xfree(stats_buffer);
+     return -EFAULT;
+}
+
+/*eof*/
diff --git a/xen/acm/acm_simple_type_enforcement_hooks.c b/xen/acm/acm_simple_type_enforcement_hooks.c
new file mode 100644 (file)
index 0000000..17e75de
--- /dev/null
@@ -0,0 +1,638 @@
+/****************************************************************
+ * acm_simple_type_enforcement_hooks.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *         support for network order binary policies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype Simple Type Enforcement for Xen
+ *     STE allows to control which domains can setup sharing
+ *     (eventchannels right now) with which other domains. Hooks
+ *     are defined and called throughout Xen when domains bind to
+ *     shared resources (setup eventchannels) and a domain is allowed
+ *     to setup sharing with another domain if and only if both domains
+ *     share at least on common type.
+ *
+ */
+#include <xen/lib.h>
+#include <asm/types.h>
+#include <asm/current.h>
+#include <acm/acm_hooks.h>
+#include <asm/atomic.h>
+#include <acm/acm_endian.h>
+
+/* local cache structures for chinese wall policy */
+struct ste_binary_policy ste_bin_pol;
+
+static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
+       int i;
+       for(i=0; i< ste_bin_pol.max_types; i++)
+               if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] && 
+                    ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
+                       printkd("%s: common type #%02x.\n", __func__, i);
+                       return 1;
+               }
+       return 0;
+}
+
+/* Helper function: return = (subj and obj share a common type) */
+static int share_common_type(struct domain *subj, struct domain *obj)
+{
+       ssidref_t ref_s, ref_o;
+       int ret;
+
+       if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
+               return 0;
+       read_lock(&acm_bin_pol_rwlock);
+       /* lookup the policy-local ssids */
+       ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                   (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
+       ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                   (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
+        /* check whether subj and obj share a common ste type */
+       ret = have_common_type(ref_s, ref_o);
+       read_unlock(&acm_bin_pol_rwlock);
+       return ret;
+}
+
+/*
+ * Initializing chinese wall policy (will be filled by policy partition
+ * using setpolicy command)
+ */
+int acm_init_ste_policy(void)
+{
+       /* minimal startup policy; policy write-locked already */
+       ste_bin_pol.max_types = 1;
+       ste_bin_pol.max_ssidrefs = 1;
+       ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 1);
+       
+       if (ste_bin_pol.ssidrefs == NULL)
+               return ACM_INIT_SSID_ERROR;
+
+       /* initialize state */
+       ste_bin_pol.ssidrefs[0] = 1;
+
+       /* init stats */
+       atomic_set(&(ste_bin_pol.ec_eval_count), 0);
+       atomic_set(&(ste_bin_pol.ec_denied_count), 0); 
+       atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
+       atomic_set(&(ste_bin_pol.gt_eval_count), 0);
+       atomic_set(&(ste_bin_pol.gt_denied_count), 0); 
+       atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
+       return ACM_OK;
+}
+
+
+/* ste initialization function hooks */
+static int
+ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref)
+{
+       int i;
+       struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid); 
+       traceprintk("%s.\n", __func__);
+
+       if (ste_ssidp == NULL)
+               return ACM_INIT_SSID_ERROR;
+
+       /* get policy-local ssid reference */
+       ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
+       if (ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) {
+               printkd("%s: ERROR ste_ssidref (%x) > max(%x).\n",
+                       __func__, ste_ssidp->ste_ssidref, ste_bin_pol.max_ssidrefs-1);
+               xfree(ste_ssidp);
+               return ACM_INIT_SSID_ERROR;
+       }
+       /* clean ste cache */
+       for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+               ste_ssidp->ste_cache[i].valid = FREE;
+
+       (*ste_ssid) = ste_ssidp;
+       printkd("%s: determined ste_ssidref to %x.\n", 
+              __func__, ste_ssidp->ste_ssidref);
+       return ACM_OK;
+}
+
+
+static void
+ste_free_domain_ssid(void *ste_ssid)
+{
+       traceprintk("%s.\n", __func__);
+       if (ste_ssid != NULL)
+               xfree(ste_ssid);
+       return;
+}
+
+/* dump type enforcement cache; policy read-locked already */
+static int 
+ste_dump_policy(u8 *buf, u16 buf_size) {
+     struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
+     int ret = 0;
+
+     ste_buf->ste_max_types = htons(ste_bin_pol.max_types);
+     ste_buf->ste_max_ssidrefs = htons(ste_bin_pol.max_ssidrefs);
+     ste_buf->policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+     ste_buf->ste_ssid_offset = htons(sizeof(struct acm_ste_policy_buffer));
+     ret = ntohs(ste_buf->ste_ssid_offset) +
+            sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
+
+     /* now copy buffer over */
+     arrcpy(buf + ntohs(ste_buf->ste_ssid_offset),
+           ste_bin_pol.ssidrefs,
+           sizeof(domaintype_t),
+             ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
+
+     return ret;
+}
+
+/* ste_init_state is called when a policy is changed to detect violations (return != 0).
+ * from a security point of view, we simulate that all running domains are re-started and
+ * all sharing decisions are replayed to detect violations or current sharing behavior
+ * (right now: event_channels, future: also grant_tables)
+ */ 
+static int
+ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
+{
+    int violation = 1;
+    struct ste_ssid *ste_ssid, *ste_rssid;
+    ssidref_t ste_ssidref, ste_rssidref;
+    struct domain **pd, *rdom;
+    domid_t rdomid;
+    grant_entry_t sha_copy;
+    int port, i;
+
+    read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
+    /* go through all domains and adjust policy as if this domain was started now */
+    pd = &domain_list;
+    for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+           ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                (struct acm_ssid_domain *)(*pd)->ssid);
+           ste_ssidref = ste_ssid->ste_ssidref;
+           traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
+                   __func__, (*pd)->domain_id, ste_ssidref);
+           /* a) check for event channel conflicts */
+           for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
+                   spin_lock(&(*pd)->evtchn_lock);
+                   if ((*pd)->evtchn[port] == NULL) {
+                            spin_unlock(&(*pd)->evtchn_lock);
+                           continue;
+                   }
+                   if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
+                           rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
+                           rdomid = rdom->domain_id;
+                           /* rdom now has remote domain */
+                           ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                                 (struct acm_ssid_domain *)(rdom->ssid));
+                           ste_rssidref = ste_rssid->ste_ssidref;
+                   } else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
+                           rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
+                           if ((rdom = find_domain_by_id(rdomid)) == NULL) {
+                                   printk("%s: Error finding domain to id %x!\n", __func__, rdomid);
+                                   goto out;
+                           }
+                           /* rdom now has remote domain */
+                           ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                                 (struct acm_ssid_domain *)(rdom->ssid));
+                           ste_rssidref = ste_rssid->ste_ssidref;
+                           put_domain(rdom);
+                   } else {
+                           spin_unlock(&(*pd)->evtchn_lock);
+                           continue; /* port unused */
+                   }
+                   spin_unlock(&(*pd)->evtchn_lock);
+
+                   /* rdom now has remote domain */
+                   ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                            (struct acm_ssid_domain *)(rdom->ssid));
+                   ste_rssidref = ste_rssid->ste_ssidref;
+                   traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n", 
+                           __func__, (*pd)->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);  
+                   /* check whether on subj->ssid, obj->ssid share a common type*/
+                   if (!have_common_type(ste_ssidref, ste_rssidref)) {
+                           printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
+                                   __func__, (*pd)->domain_id, rdomid);
+                           goto out;
+                   }
+           }   
+           /* b) check for grant table conflicts on shared pages */
+           if ((*pd)->grant_table->shared == NULL) {
+                   printkd("%s: Grant ... sharing for domain %x not setup!\n", __func__, (*pd)->domain_id);
+                   continue;
+           }
+           for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) {
+                   sha_copy =  (*pd)->grant_table->shared[i];
+                   if ( sha_copy.flags ) {
+                           printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
+                                   __func__, (*pd)->domain_id, i, sha_copy.flags, sha_copy.domid, 
+                                   (unsigned long)sha_copy.frame);
+                           rdomid = sha_copy.domid;
+                           if ((rdom = find_domain_by_id(rdomid)) == NULL) {
+                                   printkd("%s: domain not found ERROR!\n", __func__);
+                                   goto out;
+                           };
+                           /* rdom now has remote domain */
+                           ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                                                 (struct acm_ssid_domain *)(rdom->ssid));
+                           ste_rssidref = ste_rssid->ste_ssidref;
+                           put_domain(rdom);
+                           if (!have_common_type(ste_ssidref, ste_rssidref)) {
+                                   printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
+                                           __func__, (*pd)->domain_id, rdomid);
+                                   goto out;
+                           }
+                   }
+           }
+    }
+    violation = 0;
+ out:
+    read_unlock(&domlist_lock);
+    return violation;
+    /* returning "violation != 0" means that existing sharing between domains would not 
+     * have been allowed if the new policy had been enforced before the sharing; for ste, 
+     * this means that there are at least 2 domains that have established sharing through 
+     * event-channels or grant-tables but these two domains don't have no longer a common 
+     * type in their typesets referenced by their ssidrefs */
+}
+
+/* set new policy; policy write-locked already */
+static int
+ste_set_policy(u8 *buf, u16 buf_size) 
+{
+     struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
+     void *ssidrefsbuf;
+     struct ste_ssid *ste_ssid;
+     struct domain **pd;
+     int i;
+
+     /* Convert endianess of policy */
+     ste_buf->policy_code = ntohs(ste_buf->policy_code);
+     ste_buf->ste_max_types = ntohs(ste_buf->ste_max_types);
+     ste_buf->ste_max_ssidrefs = ntohs(ste_buf->ste_max_ssidrefs);
+     ste_buf->ste_ssid_offset = ntohs(ste_buf->ste_ssid_offset);
+
+     /* 1. create and copy-in new ssidrefs buffer */
+     ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
+     if (ssidrefsbuf == NULL) {
+            return -ENOMEM;
+     }
+     if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
+         goto error_free;
+
+     arrcpy(ssidrefsbuf, 
+            buf + ste_buf->ste_ssid_offset,
+            sizeof(domaintype_t),
+           ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
+
+     /* 2. now re-calculate sharing decisions based on running domains; 
+      *    this can fail if new policy is conflicting with sharing of running domains 
+      *    now: reject violating new policy; future: adjust sharing through revoking sharing */
+     if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
+            printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
+            goto error_free; /* new policy conflicts with sharing of running domains */
+     }
+     /* 3. replace old policy (activate new policy) */
+     ste_bin_pol.max_types = ste_buf->ste_max_types;
+     ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
+     if (ste_bin_pol.ssidrefs) 
+            xfree(ste_bin_pol.ssidrefs);
+     ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
+
+     /* clear all ste caches */
+     read_lock(&domlist_lock);
+     pd = &domain_list;
+     for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                        (struct acm_ssid_domain *)(*pd)->ssid);
+        for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+               ste_ssid->ste_cache[i].valid = FREE;
+     }
+     read_unlock(&domlist_lock);
+     return ACM_OK;
+
+error_free:
+       printk("%s: ERROR setting policy.\n", __func__);
+       if (ssidrefsbuf != NULL) xfree(ssidrefsbuf);
+       return -EFAULT;
+}
+
+static int 
+ste_dump_stats(u8 *buf, u16 buf_len)
+{
+    struct acm_ste_stats_buffer stats;
+
+#ifdef ACM_DEBUG
+    int i;
+    struct ste_ssid *ste_ssid;
+    struct domain **pd;
+
+    printk("ste: Decision caches:\n");
+    /* go through all domains and adjust policy as if this domain was started now */
+    read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
+    pd = &domain_list;
+    for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+        printk("ste: Cache Domain %02x.\n", (*pd)->domain_id);
+       ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                        (struct acm_ssid_domain *)(*pd)->ssid);
+       for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+               printk("\t\tcache[%02x] = %s, domid=%x.\n", i,
+                      (ste_ssid->ste_cache[i].valid == VALID) ? 
+                      "VALID" : "FREE",
+                      (ste_ssid->ste_cache[i].valid == VALID) ? 
+                      ste_ssid->ste_cache[i].id : 0xffffffff);
+    }
+    read_unlock(&domlist_lock);
+    /* init stats */
+    printk("STE-Policy Security Hook Statistics:\n");
+    printk("ste: event_channel eval_count      = %x\n", atomic_read(&(ste_bin_pol.ec_eval_count)));
+    printk("ste: event_channel denied_count    = %x\n", atomic_read(&(ste_bin_pol.ec_denied_count))); 
+    printk("ste: event_channel cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.ec_cachehit_count)));
+    printk("ste:\n");
+    printk("ste: grant_table   eval_count      = %x\n", atomic_read(&(ste_bin_pol.gt_eval_count)));
+    printk("ste: grant_table   denied_count    = %x\n", atomic_read(&(ste_bin_pol.gt_denied_count))); 
+    printk("ste: grant_table   cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.gt_cachehit_count)));
+#endif
+
+    if (buf_len < sizeof(struct acm_ste_stats_buffer))
+           return -ENOMEM;
+
+    /* now send the hook counts to user space */
+    stats.ec_eval_count = htonl(atomic_read(&ste_bin_pol.ec_eval_count));
+    stats.gt_eval_count = htonl(atomic_read(&ste_bin_pol.gt_eval_count));
+    stats.ec_denied_count = htonl(atomic_read(&ste_bin_pol.ec_denied_count));
+    stats.gt_denied_count = htonl(atomic_read(&ste_bin_pol.gt_denied_count)); 
+    stats.ec_cachehit_count = htonl(atomic_read(&ste_bin_pol.ec_cachehit_count));
+    stats.gt_cachehit_count = htonl(atomic_read(&ste_bin_pol.gt_cachehit_count));
+    memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
+    return sizeof(struct acm_ste_stats_buffer);
+}
+
+
+/* we need to go through this before calling the hooks,
+ * returns 1 == cache hit */
+static int inline
+check_cache(struct domain *dom, domid_t rdom) {
+       struct ste_ssid *ste_ssid;
+       int i;
+
+       printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
+       ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                        (struct acm_ssid_domain *)(dom)->ssid);
+
+       for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
+               if ((ste_ssid->ste_cache[i].valid == VALID) &&
+                   (ste_ssid->ste_cache[i].id == rdom)) {
+                       printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+
+/* we only get here if there is NO entry yet; no duplication check! */
+static void inline
+cache_result(struct domain *subj, struct domain *obj) {
+       struct ste_ssid *ste_ssid;
+       int i;
+       printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
+       ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                        (struct acm_ssid_domain *)(subj)->ssid);
+       for(i=0; i< ACM_TE_CACHE_SIZE; i++)
+               if (ste_ssid->ste_cache[i].valid == FREE)
+                       break;
+       if (i< ACM_TE_CACHE_SIZE) {
+               ste_ssid->ste_cache[i].valid = VALID;
+               ste_ssid->ste_cache[i].id = obj->domain_id;
+       } else
+               printk ("Cache of dom %x is full!\n", subj->domain_id);
+}
+
+/* deletes entries for domain 'id' from all caches (re-use) */
+static void inline
+clean_id_from_cache(domid_t id) 
+{
+    struct ste_ssid *ste_ssid;
+    int i;
+    struct domain **pd;
+
+    printkd("deleting cache for dom %x.\n", id);
+
+    read_lock(&domlist_lock); /* look through caches of all domains */
+    pd = &domain_list;
+    for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+       ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
+                        (struct acm_ssid_domain *)(*pd)->ssid);
+       for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+           if ((ste_ssid->ste_cache[i].valid == VALID) &&
+               (ste_ssid->ste_cache[i].id = id))
+                   ste_ssid->ste_cache[i].valid = FREE;
+    }
+    read_unlock(&domlist_lock);
+}
+
+/***************************
+ * Authorization functions
+ **************************/
+
+static int 
+ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{      
+    /* check for ssidref in range for policy */
+    ssidref_t ste_ssidref;
+    traceprintk("%s.\n", __func__);
+
+    read_lock(&acm_bin_pol_rwlock);
+    ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
+    if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
+       printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
+       read_unlock(&acm_bin_pol_rwlock);
+       return ACM_ACCESS_DENIED; /* catching and indicating config error */
+    }
+    if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
+       printk("%s: ERROR ste_ssidref > max(%x).\n", 
+              __func__, ste_bin_pol.max_ssidrefs-1);
+       read_unlock(&acm_bin_pol_rwlock);
+       return ACM_ACCESS_DENIED;
+    }
+    read_unlock(&acm_bin_pol_rwlock);
+    return ACM_ACCESS_PERMITTED;
+}
+
+static void 
+ste_post_domain_destroy(void *subject_ssid, domid_t id)
+{
+    /* clean all cache entries for destroyed domain (might be re-used) */
+    clean_id_from_cache(id);
+}
+
+/* -------- EVENTCHANNEL OPERATIONS -----------*/
+static int
+ste_pre_eventchannel_unbound(domid_t id) {
+       struct domain *subj, *obj;
+       int ret;
+       traceprintk("%s: dom%x-->dom%x.\n", 
+                   __func__, current->domain->domain_id, id);
+
+       if (check_cache(current->domain, id)) {
+               atomic_inc(&ste_bin_pol.ec_cachehit_count);
+               return ACM_ACCESS_PERMITTED;
+       }
+       atomic_inc(&ste_bin_pol.ec_eval_count);
+       subj = current->domain;
+       obj = find_domain_by_id(id);
+
+       if (share_common_type(subj, obj)) {
+               cache_result(subj, obj);
+               ret = ACM_ACCESS_PERMITTED;
+       } else {
+               atomic_inc(&ste_bin_pol.ec_denied_count); 
+               ret = ACM_ACCESS_DENIED;        
+       }
+       if (obj != NULL)
+               put_domain(obj);
+       return ret;
+}
+
+static int
+ste_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
+{
+       struct domain *subj, *obj;
+       int ret;
+       traceprintk("%s: dom%x-->dom%x.\n", __func__,
+                   (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
+                   (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
+
+       /* following is a bit longer but ensures that we
+         * "put" only domains that we where "find"-ing 
+        */
+       if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
+       if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
+
+       subj = find_domain_by_id(id1);
+       obj  = find_domain_by_id(id2);
+       if ((subj == NULL) || (obj == NULL)) {
+               ret = ACM_ACCESS_DENIED;
+               goto out;
+       }
+       /* cache check late, but evtchn is not on performance critical path */
+       if (check_cache(subj, obj->domain_id)) {
+               atomic_inc(&ste_bin_pol.ec_cachehit_count);
+               ret = ACM_ACCESS_PERMITTED;
+               goto out;
+       }
+       atomic_inc(&ste_bin_pol.ec_eval_count);
+
+       if (share_common_type(subj, obj)) {
+               cache_result(subj, obj);
+               ret = ACM_ACCESS_PERMITTED;
+       } else {
+               atomic_inc(&ste_bin_pol.ec_denied_count); 
+               ret = ACM_ACCESS_DENIED;        
+       }
+ out:
+       if (obj != NULL)
+               put_domain(obj);
+       if (subj != NULL)
+               put_domain(subj);
+       return ret;
+}
+
+/* -------- SHARED MEMORY OPERATIONS -----------*/
+
+static int
+ste_pre_grant_map_ref (domid_t id) {
+       struct domain *obj, *subj;
+       int ret;
+       traceprintk("%s: dom%x-->dom%x.\n", __func__,
+                   current->domain->domain_id, id);
+
+       if (check_cache(current->domain, id)) {
+               atomic_inc(&ste_bin_pol.gt_cachehit_count);
+               return ACM_ACCESS_PERMITTED;
+       }
+       atomic_inc(&ste_bin_pol.gt_eval_count);
+       subj = current->domain;
+       obj = find_domain_by_id(id);
+
+       if (share_common_type(subj, obj)) {
+               cache_result(subj, obj);
+               ret = ACM_ACCESS_PERMITTED;
+       } else {
+               atomic_inc(&ste_bin_pol.gt_denied_count); 
+               printkd("%s: ACCESS DENIED!\n", __func__);
+               ret = ACM_ACCESS_DENIED;        
+       }
+       if (obj != NULL)
+               put_domain(obj);
+       return ret;
+}
+
+/* since setting up grant tables involves some implicit information
+   flow from the creating domain to the domain that is setup, we 
+   check types in addition to the general authorization */
+static int
+ste_pre_grant_setup (domid_t id) {
+       struct domain *obj, *subj;
+       int ret;
+       traceprintk("%s: dom%x-->dom%x.\n", __func__,
+                   current->domain->domain_id, id);
+
+       if (check_cache(current->domain, id)) {
+               atomic_inc(&ste_bin_pol.gt_cachehit_count);
+               return ACM_ACCESS_PERMITTED;
+       }
+       atomic_inc(&ste_bin_pol.gt_eval_count);
+       /* a) check authorization (eventually use specific capabilities) */
+       if (!IS_PRIV(current->domain)) {
+               printk("%s: Grant table management authorization denied ERROR!\n", __func__);
+               return ACM_ACCESS_DENIED;
+       }
+       /* b) check types */
+       subj = current->domain;
+       obj = find_domain_by_id(id);
+
+       if (share_common_type(subj, obj)) {
+               cache_result(subj, obj);
+               ret = ACM_ACCESS_PERMITTED;
+       } else {
+               atomic_inc(&ste_bin_pol.gt_denied_count); 
+               ret = ACM_ACCESS_DENIED;        
+       }
+       if (obj != NULL)
+               put_domain(obj);
+       return ret;
+}
+
+/* now define the hook structure similarly to LSM */
+struct acm_operations acm_simple_type_enforcement_ops = {
+       /* policy management services */
+       .init_domain_ssid               = ste_init_domain_ssid,
+       .free_domain_ssid               = ste_free_domain_ssid,
+       .dump_binary_policy             = ste_dump_policy,
+       .set_binary_policy              = ste_set_policy,
+       .dump_statistics                = ste_dump_stats,
+       /* domain management control hooks */
+       .pre_domain_create              = ste_pre_domain_create,
+       .post_domain_create             = NULL,
+       .fail_domain_create             = NULL,
+       .post_domain_destroy            = ste_post_domain_destroy,
+       /* event channel control hooks */
+       .pre_eventchannel_unbound       = ste_pre_eventchannel_unbound,
+       .fail_eventchannel_unbound      = NULL,
+       .pre_eventchannel_interdomain   = ste_pre_eventchannel_interdomain,
+       .fail_eventchannel_interdomain  = NULL,
+       /* grant table control hooks */
+       .pre_grant_map_ref              = ste_pre_grant_map_ref,
+       .fail_grant_map_ref             = NULL,
+       .pre_grant_setup                = ste_pre_grant_setup,
+       .fail_grant_setup               = NULL,
+};
index b0ebecfcee3aab4f44dc67c695a9cc098a05acde..ca7cf17aca1c898f066284067a55c7a9bfa362a7 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/desc.h>
 #include <asm/shadow.h>
 #include <asm/e820.h>
+#include <public/acm_dom0_setup.h>
 
 extern void dmi_scan_machine(void);
 extern void generic_apic_probe(void);
@@ -393,12 +394,17 @@ void __init __start_xen(multiboot_info_t *mbi)
 
     shadow_mode_init();
 
+    /* initialize access control security module */
+    acm_init();
+
     /* Create initial domain 0. */
     dom0 = do_createdomain(0, 0);
     if ( dom0 == NULL )
         panic("Error creating domain 0\n");
 
     set_bit(_DOMF_privileged, &dom0->domain_flags);
+    /* post-create hooks sets security label */
+    acm_post_domain0_create(dom0->domain_id);
 
     /* Grab the DOM0 command line. */
     cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL);
index 475474b99ae959db786957670e8d5a7ecec896ab..93827336d4fcbdb66c1249b4648afe38af08ee27 100644 (file)
@@ -751,6 +751,7 @@ ENTRY(hypercall_table)
         .long do_boot_vcpu
         .long do_ni_hypercall       /* 25 */
         .long do_mmuext_op
+        .long do_policy_op          /* 27 */
         .rept NR_hypercalls-((.-hypercall_table)/4)
         .long do_ni_hypercall
         .endr
index 8b3dd1edbc2ac56ceb7e1c53dd378032e80a588e..ec86fc1b6290421c55b38c999c830771a5c97251 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/current.h>
 #include <public/dom0_ops.h>
 #include <public/sched_ctl.h>
+#include <acm/acm_hooks.h>
 
 extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
 extern void arch_getdomaininfo_ctxt(
@@ -91,6 +92,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
 {
     long ret = 0;
     dom0_op_t curop, *op = &curop;
+    void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
 
     if ( !IS_PRIV(current->domain) )
         return -EPERM;
@@ -101,6 +103,9 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
     if ( op->interface_version != DOM0_INTERFACE_VERSION )
         return -EACCES;
 
+    if ( acm_pre_dom0_op(op, &ssid) )
+        return -EACCES;
+
     switch ( op->cmd )
     {
 
@@ -357,6 +362,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
             ((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
             d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
 
+        if (d->ssid != NULL)
+            op->u.getdomaininfo.ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
+        else    
+            op->u.getdomaininfo.ssidref = ACM_DEFAULT_SSID;
+
         op->u.getdomaininfo.tot_pages   = d->tot_pages;
         op->u.getdomaininfo.max_pages   = d->max_pages;
         op->u.getdomaininfo.shared_info_frame = 
@@ -493,7 +503,10 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
         ret = arch_do_dom0_op(op,u_dom0_op);
 
     }
-
+    if (!ret)
+        acm_post_dom0_op(op, ssid);
+    else
+        acm_fail_dom0_op(op, ssid);
     return ret;
 }
 
index 6f6e70766763678bfdde204c9b6fb6b421c82182..29d10ef3d2159a247deca49c6d744a883c9c2c40 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <public/xen.h>
 #include <public/event_channel.h>
+#include <acm/acm_hooks.h>
 
 #define bucket_from_port(d,p) \
     ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
@@ -587,6 +588,9 @@ long do_event_channel_op(evtchn_op_t *uop)
     if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
         return -EFAULT;
 
+    if (acm_pre_event_channel(&op))
+        return -EACCES;
+
     switch ( op.cmd )
     {
     case EVTCHNOP_alloc_unbound:
index 683a051df3b8042b8d399bc4087a4d721900b008..9e7b7223e942f4c98cb2a8e5550af05b0bf29bd6 100644 (file)
@@ -30,6 +30,7 @@
 #include <xen/sched.h>
 #include <xen/shadow.h>
 #include <xen/mm.h>
+#include <acm/acm_hooks.h>
 
 #define PIN_FAIL(_lbl, _rc, _f, _a...)   \
     do {                           \
@@ -357,6 +358,11 @@ __gnttab_map_grant_ref(
         return GNTST_bad_gntref;
     }
 
+    if (acm_pre_grant_map_ref(dom)) {
+        (void)__put_user(GNTST_permission_denied, &uop->handle);
+        return GNTST_permission_denied;
+    }
+
     if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
          unlikely(ld == rd) )
     {
diff --git a/xen/common/policy_ops.c b/xen/common/policy_ops.c
new file mode 100644 (file)
index 0000000..ff2b2f9
--- /dev/null
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *policy_ops.c
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * Process policy command requests from guest OS.
+ *
+ */
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <public/policy_ops.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/trace.h>
+#include <xen/console.h>
+#include <asm/shadow.h>
+#include <public/sched_ctl.h>
+#include <acm/acm_hooks.h>
+
+/* function prototypes defined in acm/acm_policy.c */
+int acm_set_policy(void *buf, u16 buf_size, u16 policy);
+int acm_get_policy(void *buf, u16 buf_size);
+int acm_dump_statistics(void *buf, u16 buf_size);
+
+typedef enum policyoperation {
+       POLICY,     /* access to policy interface (early drop) */
+       GETPOLICY,  /* dump policy cache */
+       SETPOLICY,  /* set policy cache (controls security) */
+       DUMPSTATS   /* dump policy statistics */
+} policyoperation_t;
+
+int
+acm_authorize_policyops(struct domain *d, policyoperation_t pops)
+{
+       /* currently, all policy management functions are restricted to privileged domains,
+        * soon we will introduce finer-grained privileges for policy operations 
+        */
+       if (!IS_PRIV(d)) {
+               printk("%s: Policy management authorization denied ERROR!\n", __func__);
+               return ACM_ACCESS_DENIED;
+       }
+       return ACM_ACCESS_PERMITTED;
+}
+
+long do_policy_op(policy_op_t *u_policy_op)
+{
+    long ret = 0;
+    policy_op_t curop, *op = &curop;
+
+    /* check here policy decision for policy commands */
+    /* for now allow DOM0 only, later indepedently    */
+    if (acm_authorize_policyops(current->domain, POLICY))
+           return -EACCES;
+
+    if ( copy_from_user(op, u_policy_op, sizeof(*op)) )
+        return -EFAULT;
+
+    if ( op->interface_version != POLICY_INTERFACE_VERSION )
+        return -EACCES;
+
+    switch ( op->cmd )
+    {
+    case POLICY_SETPOLICY:
+    {
+        if (acm_authorize_policyops(current->domain, SETPOLICY))
+               return -EACCES;
+       printkd("%s: setting policy.\n", __func__);
+       ret = acm_set_policy(op->u.setpolicy.pushcache, op->u.setpolicy.pushcache_size, op->u.setpolicy.policy_type);
+        if (ret == ACM_OK)
+            ret = 0;
+        else
+            ret = -ESRCH;
+    }
+    break;
+
+    case POLICY_GETPOLICY:
+    {
+        if (acm_authorize_policyops(current->domain, GETPOLICY))
+               return -EACCES;
+        printkd("%s: getting policy.\n", __func__);
+       ret = acm_get_policy(op->u.getpolicy.pullcache, op->u.getpolicy.pullcache_size);
+        if (ret == ACM_OK)
+            ret = 0;
+        else
+            ret = -ESRCH;
+    }
+    break;
+
+    case POLICY_DUMPSTATS:
+    {
+        if (acm_authorize_policyops(current->domain, DUMPSTATS))
+               return -EACCES;
+       printkd("%s: dumping statistics.\n", __func__);
+       ret = acm_dump_statistics(op->u.dumpstats.pullcache, op->u.dumpstats.pullcache_size);
+        if (ret == ACM_OK)
+            ret = 0;
+        else
+            ret = -ESRCH;
+    }
+    break;
+
+    default:
+        ret = -ESRCH;
+
+    }
+    return ret;
+}
diff --git a/xen/include/acm/acm_core.h b/xen/include/acm/acm_core.h
new file mode 100644 (file)
index 0000000..e404b45
--- /dev/null
@@ -0,0 +1,117 @@
+/****************************************************************
+ * acm_core.h 
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype header file describing core data types and constants
+ *    for the access control module and relevant policies
+ *
+ */
+#ifndef _ACM_CORE_H
+#define _ACM_CORE_H
+
+#include <xen/spinlock.h>
+#include <public/acm.h>
+#include <public/policy_ops.h>
+
+/* Xen-internal representation of the binary policy */
+struct acm_binary_policy {
+       u16 primary_policy_code;
+       u16 secondary_policy_code;
+       void *primary_binary_policy;                                 
+       void *secondary_binary_policy;
+       
+};
+
+struct chwall_binary_policy {
+       u16 max_types;
+       u16 max_ssidrefs;
+       u16 max_conflictsets;
+       domaintype_t *ssidrefs;                 /* [max_ssidrefs][max_types]    */
+       domaintype_t *conflict_aggregate_set;   /* [max_types]                  */
+       domaintype_t *running_types;            /* [max_types]                  */
+       domaintype_t *conflict_sets;            /* [max_conflictsets][max_types]*/
+};
+
+struct ste_binary_policy {
+       u16 max_types;
+       u16 max_ssidrefs;
+       domaintype_t *ssidrefs;                 /* [max_ssidrefs][max_types]    */
+       atomic_t ec_eval_count, gt_eval_count;
+       atomic_t ec_denied_count, gt_denied_count; 
+       atomic_t ec_cachehit_count, gt_cachehit_count;
+};
+
+/* global acm policy */
+extern struct acm_binary_policy acm_bin_pol;
+extern struct chwall_binary_policy chwall_bin_pol;
+extern struct ste_binary_policy ste_bin_pol;
+/* use the lock when reading / changing binary policy ! */
+extern rwlock_t acm_bin_pol_rwlock;
+
+/* subject and object type definitions */
+enum acm_datatype { DOMAIN };
+
+/* defines number of access decisions to other domains can be cached
+ * one entry per domain, TE does not distinguish evtchn or grant_table */
+#define ACM_TE_CACHE_SIZE      8
+enum acm_ste_flag { VALID, FREE };
+
+/* cache line:
+ * if cache_line.valid==VALID, then
+ *    STE decision is cached as "permitted" 
+ *                 on domain cache_line.id
+ */
+struct acm_ste_cache_line {
+       enum acm_ste_flag valid;
+       domid_t id;
+};
+
+/* general definition of a subject security id */
+struct acm_ssid_domain {
+       enum acm_datatype datatype;             /* type of subject (e.g., partition) */
+       ssidref_t         ssidref;              /* combined security reference */
+       void              *primary_ssid;        /* primary policy ssid part (e.g. chinese wall) */
+       void              *secondary_ssid;      /* secondary policy ssid part (e.g. type enforcement) */
+       struct domain     *subject;             /* backpointer to subject structure */
+       domid_t           domainid;             /* replicate id */
+};
+
+/* chinese wall ssid type */
+struct chwall_ssid {
+       ssidref_t chwall_ssidref;
+};
+
+/* simple type enforcement ssid type */
+struct ste_ssid {
+       ssidref_t ste_ssidref;
+       struct acm_ste_cache_line ste_cache[ACM_TE_CACHE_SIZE]; /* decision cache */
+};
+
+/* macros to access ssidref for primary / secondary policy 
+ *     primary ssidref   = lower 16 bit
+ *      secondary ssidref = higher 16 bit
+ */
+#define GET_SSIDREF(POLICY, ssidref) \
+       ((POLICY) == acm_bin_pol.primary_policy_code) ? \
+       ((ssidref) & 0xffff) : ((ssidref) >> 16)
+
+/* macros to access ssid pointer for primary / secondary policy */
+#define GET_SSIDP(POLICY, ssid) \
+       ((POLICY) == acm_bin_pol.primary_policy_code) ? \
+       ((ssid)->primary_ssid) : ((ssid)->secondary_ssid)
+
+/* protos */
+int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
+int acm_free_domain_ssid(struct acm_ssid_domain *ssid);
+
+#endif
+
diff --git a/xen/include/acm/acm_endian.h b/xen/include/acm/acm_endian.h
new file mode 100644 (file)
index 0000000..fd7229b
--- /dev/null
@@ -0,0 +1,88 @@
+/****************************************************************
+ * acm_endian.h 
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * 
+ * Contributions:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype header file defining endian-dependent functions for the
+ * big-endian policy interface
+ *
+ */
+#ifndef _ACM_ENDIAN_H
+#define _ACM_ENDIAN_H
+
+/* don't use these functions in performance critical sections! */
+
+/* set during initialization by testing */
+extern u8 little_endian;
+
+static inline u32 ntohl(u32 x) 
+{
+    if (little_endian)
+        return 
+           ( (((x) >> 24) & 0xff      )| 
+             (((x) >>  8) & 0xff00    )| 
+             (((x) <<  8) & 0xff0000  )|
+             (((x) << 24) & 0xff000000) );
+    else
+        return x;
+}
+
+static inline u16 ntohs(u16 x) 
+{
+    if (little_endian)
+        return 
+           ( (((x) >> 8) & 0xff   )|
+             (((x) << 8) & 0xff00 ) );
+    else
+       return x;
+}
+
+#define htonl(x) ntohl(x)
+#define htons(x) ntohs(x)
+
+static inline void arrcpy16(u16 *dest, const u16 *src, size_t n)
+{
+    unsigned int i = 0;
+    while (i < n) {
+               dest[i] = htons(src[i]);
+               i++;
+    }
+}
+
+static inline void arrcpy32(u32 *dest, const u32 *src, size_t n)
+{
+    unsigned int i = 0;
+    while (i < n) {
+       dest[i] = htonl(src[i]);
+       i++;
+    }
+}
+
+static inline void arrcpy(void *dest, const void *src, unsigned int elsize, size_t n)
+{
+    switch (elsize) {
+    case sizeof(u16):
+        arrcpy16((u16 *)dest, (u16 *)src, n);
+        break;
+
+    case sizeof(u32):
+        arrcpy32((u32 *)dest, (u32 *)src, n);
+        break;
+
+    default:
+        memcpy(dest, src, elsize*n);
+    }
+}
+
+#endif
diff --git a/xen/include/acm/acm_hooks.h b/xen/include/acm/acm_hooks.h
new file mode 100644 (file)
index 0000000..534d919
--- /dev/null
@@ -0,0 +1,337 @@
+/****************************************************************
+ * acm_hooks.h 
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * acm header file implementing the global (policy-independent)
+ *      sHype hooks that are called throughout Xen.
+ * 
+ */
+#ifndef _ACM_HOOKS_H
+#define _ACM_HOOKS_H
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/acm.h>
+#include <acm/acm_core.h>
+#include <public/dom0_ops.h>
+#include <public/event_channel.h>
+#include <asm/current.h>
+
+/* if ACM_TRACE_MODE defined, all hooks should
+ * print a short trace message */
+/* #define ACM_TRACE_MODE */
+
+#ifdef ACM_TRACE_MODE
+#  define traceprintk(fmt, args...) printk(fmt,## args)
+#else
+#  define traceprintk(fmt, args...)
+#endif
+
+/* global variables */
+extern struct acm_operations *acm_primary_ops;
+extern struct acm_operations *acm_secondary_ops;
+
+/**********************************************************************************************
+ * HOOK structure and meaning (justifies a few words about our model):
+ * 
+ * General idea: every policy-controlled system operation is reflected in a 
+ *               transaction in the system's security state
+ *
+ *     Keeping the security state consistent requires "atomic" transactions.
+ *      The name of the hooks to place around policy-controlled transactions
+ *      reflects this. If authorizations do not involve security state changes,
+ *      then and only then POST and FAIL hooks remain empty since we don't care
+ *      about the eventual outcome of the operation from a security viewpoint.
+ *
+ *     PURPOSE of hook types:
+ *      ======================
+ *      PRE-Hooks
+ *             a) general authorization to guard a controlled system operation
+ *             b) prepare security state change (means: fail hook must be able to "undo" this)
+ *
+ *     POST-Hooks
+ *             a) commit prepared state change
+ *
+ *      FAIL-Hooks
+ *             a) roll-back prepared security state change from PRE-Hook
+ *
+ *
+ *      PLACEMENT of hook types:
+ *      ========================
+ *     PRE-Hooks must be called:
+ *             a) before a guarded/controlled system operation is started
+ *             (return is ACM_ACCESS_PERMITTED or ACM_ACCESS_DENIED or error)
+ *                --> operation must be aborted if return is != ACM_ACCESS_PERMITTED
+ *
+ *     POST-Hooks must be called:
+ *             a) after successful transaction (no return value; commit shall never fail)
+ *
+ *     FAIL-Hooks must be called:
+ *             a) if system transaction (operation) fails somewhen after calling the PRE-hook
+ *                (obviously the POST-Hook is not called in this case)
+ *             b) if another (secondary) policy denies access in its PRE-Hook
+ *                (policy layering is useful but requires additional handling)
+ *
+ *
+ *
+ *       Hook model from a security transaction viewpoint:
+ *
+ *          start-sys-ops--> prepare ----succeed-----> commit --> sys-ops success
+ *                          (pre-hook)  \           (post-hook)
+ *                                       \
+ *                                       fail
+ *                                         \
+ *                                          \
+ *                                        roll-back
+ *                                       (fail-hook)
+ *                                             \
+ *                                            sys-ops error
+ *
+ *************************************************************************************************/
+
+struct acm_operations {
+       /* policy management functions (must always be defined!) */
+       int  (*init_domain_ssid)                (void **ssid, ssidref_t ssidref);
+       void (*free_domain_ssid)                (void *ssid);
+       int  (*dump_binary_policy)              (u8 *buffer, u16 buf_size);
+       int  (*set_binary_policy)               (u8 *buffer, u16 buf_size);     
+       int  (*dump_statistics)                 (u8 *buffer, u16 buf_size);
+       /* domain management control hooks (can be NULL) */
+       int  (*pre_domain_create)               (void *subject_ssid, ssidref_t ssidref);
+       void (*post_domain_create)              (domid_t domid, ssidref_t ssidref);
+       void (*fail_domain_create)              (void *subject_ssid, ssidref_t ssidref);
+       void (*post_domain_destroy)             (void *object_ssid, domid_t id);
+       /* event channel control hooks  (can be NULL) */
+       int  (*pre_eventchannel_unbound)        (domid_t id);
+       void (*fail_eventchannel_unbound)       (domid_t id);
+       int  (*pre_eventchannel_interdomain)    (domid_t id1, domid_t id2);
+       int  (*fail_eventchannel_interdomain)   (domid_t id1, domid_t id2);
+       /* grant table control hooks (can be NULL)  */
+       int  (*pre_grant_map_ref)               (domid_t id);
+       void (*fail_grant_map_ref)              (domid_t id);
+       int  (*pre_grant_setup)                 (domid_t id);
+       void (*fail_grant_setup)                (domid_t id);
+};
+
+static inline int acm_pre_domain_create (void *subject_ssid, ssidref_t ssidref)
+{
+       if ((acm_primary_ops->pre_domain_create != NULL) && 
+                acm_primary_ops->pre_domain_create (subject_ssid, ssidref))
+               return ACM_ACCESS_DENIED;
+       else if ((acm_secondary_ops->pre_domain_create != NULL) && 
+                acm_secondary_ops->pre_domain_create (subject_ssid, ssidref)) {
+               /* roll-back primary */
+               if (acm_primary_ops->fail_domain_create != NULL)
+                       acm_primary_ops->fail_domain_create (subject_ssid, ssidref);
+               return ACM_ACCESS_DENIED;
+       } else
+               return ACM_ACCESS_PERMITTED;
+}
+
+static inline void acm_post_domain_create (domid_t domid, ssidref_t ssidref)
+{
+       if (acm_primary_ops->post_domain_create != NULL)
+               acm_primary_ops->post_domain_create (domid, ssidref);
+       if (acm_secondary_ops->post_domain_create != NULL)
+               acm_secondary_ops->post_domain_create (domid, ssidref);
+}
+
+static inline void acm_fail_domain_create (void *subject_ssid, ssidref_t ssidref)
+{
+       if (acm_primary_ops->fail_domain_create != NULL)
+               acm_primary_ops->fail_domain_create (subject_ssid, ssidref);
+       if (acm_secondary_ops->fail_domain_create != NULL)
+               acm_secondary_ops->fail_domain_create (subject_ssid, ssidref);
+}
+
+static inline void acm_post_domain_destroy (void *object_ssid, domid_t id)
+{
+       if (acm_primary_ops->post_domain_destroy != NULL)
+               acm_primary_ops->post_domain_destroy (object_ssid, id);
+       if (acm_secondary_ops->post_domain_destroy != NULL)
+               acm_secondary_ops->post_domain_destroy (object_ssid, id);
+       return;
+}
+
+/*   event channel ops */
+
+static inline int acm_pre_eventchannel_unbound (domid_t id)
+{
+       if ((acm_primary_ops->pre_eventchannel_unbound != NULL) && 
+           acm_primary_ops->pre_eventchannel_unbound (id))
+               return ACM_ACCESS_DENIED;
+       else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) && 
+                acm_secondary_ops->pre_eventchannel_unbound (id)) {
+               /* roll-back primary */
+               if (acm_primary_ops->fail_eventchannel_unbound != NULL)
+                       acm_primary_ops->fail_eventchannel_unbound (id);
+               return ACM_ACCESS_DENIED;
+       } else
+               return ACM_ACCESS_PERMITTED;
+}
+
+static inline int acm_pre_eventchannel_interdomain (domid_t id1, domid_t id2)
+{      
+       if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) &&
+           acm_primary_ops->pre_eventchannel_interdomain (id1, id2))
+               return ACM_ACCESS_DENIED;
+       else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) &&
+                acm_secondary_ops->pre_eventchannel_interdomain (id1, id2)) {
+               /* roll-back primary */
+               if (acm_primary_ops->fail_eventchannel_interdomain != NULL)
+                       acm_primary_ops->fail_eventchannel_interdomain (id1, id2);
+               return ACM_ACCESS_DENIED;
+       } else
+               return ACM_ACCESS_PERMITTED;
+}
+
+/************ Xen inline hooks ***************/
+
+/* small macro to make the hooks more readable 
+ * (eliminates hooks if NULL policy is active)
+ */
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid) 
+{ return 0; }
+#else
+static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid) 
+{
+       int ret = -EACCES;
+       struct domain *d;
+
+       switch(op->cmd) {
+       case DOM0_CREATEDOMAIN:
+               ret = acm_pre_domain_create(current->domain->ssid, op->u.createdomain.ssidref);
+               break;
+       case DOM0_DESTROYDOMAIN:
+               d = find_domain_by_id(op->u.destroydomain.domain);
+               if (d != NULL) {
+                       *ssid = d->ssid; /* save for post destroy when d is gone */
+                       /* no policy-specific hook */
+                       put_domain(d);
+                       ret = 0;
+               }
+               break;
+       default:
+               ret = 0; /* ok */
+       }
+       return ret;
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid) 
+{ return; }
+#else
+static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid) 
+{
+       switch(op->cmd) {
+       case DOM0_CREATEDOMAIN:
+               /* initialialize shared sHype security labels for new domain */
+               acm_init_domain_ssid(op->u.createdomain.domain, op->u.createdomain.ssidref);
+               acm_post_domain_create(op->u.createdomain.domain, op->u.createdomain.ssidref);
+               break;
+       case DOM0_DESTROYDOMAIN:
+               acm_post_domain_destroy(ssid, op->u.destroydomain.domain);
+               /* free security ssid for the destroyed domain (also if running null policy */
+               acm_free_domain_ssid((struct acm_ssid_domain *)ssid);
+               break;
+       }
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICy == ACM_NULL_POLICY)
+static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid) 
+{ return; }
+#else
+static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid) 
+{
+       switch(op->cmd) {
+       case DOM0_CREATEDOMAIN:
+               acm_fail_domain_create(current->domain->ssid, op->u.createdomain.ssidref);
+               break;
+       }
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_event_channel(evtchn_op_t *op) 
+{ return 0; }
+#else
+static inline int acm_pre_event_channel(evtchn_op_t *op) 
+{
+       int ret = -EACCES;
+
+       switch(op->cmd) {
+       case EVTCHNOP_alloc_unbound:
+               ret = acm_pre_eventchannel_unbound(op->u.alloc_unbound.dom);
+               break;
+       case EVTCHNOP_bind_interdomain:
+               ret = acm_pre_eventchannel_interdomain(op->u.bind_interdomain.dom1, op->u.bind_interdomain.dom2);
+               break;
+       default:
+               ret = 0; /* ok */
+       }
+       return ret;
+}
+#endif
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_grant_map_ref(domid_t id) 
+{ return 0; }
+#else
+static inline int acm_pre_grant_map_ref (domid_t id)
+{
+       if ((acm_primary_ops->pre_grant_map_ref != NULL) &&
+           acm_primary_ops->pre_grant_map_ref (id))
+               return ACM_ACCESS_DENIED;
+       else if ((acm_secondary_ops->pre_grant_map_ref != NULL) &&
+                acm_secondary_ops->pre_grant_map_ref (id)) {
+               /* roll-back primary */
+               if (acm_primary_ops->fail_grant_map_ref != NULL)
+                       acm_primary_ops->fail_grant_map_ref (id);
+               return ACM_ACCESS_DENIED;
+       } else
+               return ACM_ACCESS_PERMITTED;
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_grant_setup(domid_t id) 
+{ return 0; }
+#else
+static inline int acm_pre_grant_setup (domid_t id)
+{
+       if ((acm_primary_ops->pre_grant_setup != NULL) &&
+           acm_primary_ops->pre_grant_setup (id))
+               return ACM_ACCESS_DENIED;
+       else if ((acm_secondary_ops->pre_grant_setup != NULL) &&
+                acm_secondary_ops->pre_grant_setup (id)) {
+               /* roll-back primary */
+               if (acm_primary_ops->fail_grant_setup != NULL)
+                       acm_primary_ops->fail_grant_setup (id);
+               return ACM_ACCESS_DENIED;
+       } else
+               return ACM_ACCESS_PERMITTED;
+}
+#endif
+
+
+#endif
diff --git a/xen/include/public/acm.h b/xen/include/public/acm.h
new file mode 100644 (file)
index 0000000..31191b7
--- /dev/null
@@ -0,0 +1,161 @@
+/****************************************************************
+ * acm.h
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Stefan Berger <stefanb@watson.ibm.com> 
+ *     added network byte order support for binary policies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * sHype general access control module header file.
+ *     here are all definitions that are shared between
+ *     xen-core, guest-kernels, and applications.
+ *
+ * todo: move from static policy choice to compile option.
+ */
+
+#ifndef _XEN_PUBLIC_SHYPE_H
+#define _XEN_PUBLIC_SHYPE_H
+
+#include "xen.h"
+#include "sched_ctl.h"
+
+/* if ACM_DEBUG defined, all hooks should
+ * print a short trace message (comment it out
+ * when not in testing mode )
+ */
+/* #define ACM_DEBUG */
+
+#ifdef ACM_DEBUG
+#  define printkd(fmt, args...) printk(fmt,## args)
+#else
+#  define printkd(fmt, args...)
+#endif
+
+/* default ssid reference value if not supplied */
+#define ACM_DEFAULT_SSID       0xffffffff
+#define ACM_DEFAULT_LOCAL_SSID  0xffff
+
+/* Internal ACM ERROR types */
+#define ACM_OK                          0
+#define ACM_UNDEF                      -1
+#define ACM_INIT_SSID_ERROR            -2
+#define ACM_INIT_SOID_ERROR            -3
+#define ACM_ERROR                      -4
+
+/* External ACCESS DECISIONS */
+#define ACM_ACCESS_PERMITTED           0
+#define ACM_ACCESS_DENIED              -111
+#define ACM_NULL_POINTER_ERROR         -200
+
+#define ACM_MAX_POLICY  3
+
+#define ACM_NULL_POLICY        0
+#define ACM_CHINESE_WALL_POLICY        1
+#define ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY 2
+#define ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY 3
+
+/* policy: */
+#define ACM_POLICY_NAME(X) \
+       (X == ACM_NULL_POLICY) ? "NULL policy" : \
+       (X == ACM_CHINESE_WALL_POLICY) ? "CHINESE WALL policy" : \
+       (X == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "SIMPLE TYPE ENFORCEMENT policy" : \
+       (X == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "CHINESE WALL AND SIMPLE TYPE ENFORCEMENT policy" : \
+       "UNDEFINED policy"
+
+#ifndef ACM_USE_SECURITY_POLICY
+#define ACM_USE_SECURITY_POLICY ACM_NULL_POLICY
+#endif
+
+/* defines a ssid reference used by xen */
+typedef u32 ssidref_t;
+
+/* -------security policy relevant type definitions-------- */
+
+/* type identifier; compares to "equal" or "not equal" */
+typedef u16 domaintype_t;
+
+/* CHINESE WALL POLICY DATA STRUCTURES
+ *
+ * current accumulated conflict type set:
+ * When a domain is started and has a type that is in
+ * a conflict set, the conflicting types are incremented in
+ * the aggregate set. When a domain is destroyed, the 
+ * conflicting types to its type are decremented.
+ * If a domain has multiple types, this procedure works over
+ * all those types.
+ *
+ * conflict_aggregate_set[i] holds the number of
+ *   running domains that have a conflict with type i.
+ *
+ * running_types[i] holds the number of running domains
+ *        that include type i in their ssidref-referenced type set
+ *
+ * conflict_sets[i][j] is "0" if type j has no conflict
+ *    with type i and is "1" otherwise.
+ */
+/* high-16 = version, low-16 = check magic */
+#define ACM_MAGIC              0x0001debc
+
+/* each offset in bytes from start of the struct they
+ *   the are part of */
+/* each buffer consists of all policy information for
+ * the respective policy given in the policy code
+ */
+struct acm_policy_buffer {
+        u32 magic;
+       u32 policyversion;
+       u32 len;
+       u16 primary_policy_code;
+       u16 primary_buffer_offset;
+       u16 secondary_policy_code;
+       u16 secondary_buffer_offset;
+};
+
+struct acm_chwall_policy_buffer {
+       u16 policy_code;
+       u16 chwall_max_types;
+       u16 chwall_max_ssidrefs;
+       u16 chwall_max_conflictsets;
+       u16 chwall_ssid_offset;
+       u16 chwall_conflict_sets_offset;
+       u16 chwall_running_types_offset;
+       u16 chwall_conflict_aggregate_offset;
+};
+
+struct acm_ste_policy_buffer {
+       u16 policy_code;
+       u16 ste_max_types;
+       u16 ste_max_ssidrefs;
+       u16 ste_ssid_offset;
+};
+
+struct acm_stats_buffer {
+        u32 magic;
+       u32 policyversion;
+       u32 len;
+       u16 primary_policy_code;
+       u16 primary_stats_offset;
+       u16 secondary_policy_code;
+       u16 secondary_stats_offset;
+};
+
+struct acm_ste_stats_buffer {
+       u32 ec_eval_count;
+       u32 gt_eval_count;
+       u32 ec_denied_count;
+       u32 gt_denied_count; 
+       u32 ec_cachehit_count;
+       u32 gt_cachehit_count;
+};
+
+
+#endif
diff --git a/xen/include/public/acm_dom0_setup.h b/xen/include/public/acm_dom0_setup.h
new file mode 100644 (file)
index 0000000..6604156
--- /dev/null
@@ -0,0 +1,34 @@
+/****************************************************************
+ * acm_dom0_setup.h
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Includes necessary definitions to bring-up dom0
+ */
+#include <acm/acm_hooks.h>
+
+extern int acm_init(void);
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+
+static inline void acm_post_domain0_create(domid_t domid) 
+{ 
+       return; 
+}
+
+#else
+
+/* predefined ssidref for DOM0 used by xen when creating DOM0 */
+#define ACM_DOM0_SSIDREF       0
+
+static inline void acm_post_domain0_create(domid_t domid)
+{
+       /* initialialize shared sHype security labels for new domain */
+       acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF);
+       acm_post_domain_create(domid, ACM_DOM0_SSIDREF);
+}
+
+#endif
index 0768b8c6ae6d4a4e8a4e720d3f62fae31dd87010..3ff82b43aca5164c8ab3e08273ad91f01def9e17 100644 (file)
@@ -43,6 +43,8 @@ typedef struct sched_adjdom_cmd dom0_adjustdom_t;
 
 #define DOM0_CREATEDOMAIN      8
 typedef struct {
+    /* IN parameters */
+    u32 ssidref;
     /* IN/OUT parameters. */
     /* Identifier for new domain (auto-allocate if zero is specified). */
     domid_t domain;
@@ -88,6 +90,7 @@ typedef struct {
     u32      n_vcpu;
     s32      vcpu_to_cpu[MAX_VIRT_CPUS];  /* current mapping   */
     cpumap_t cpumap[MAX_VIRT_CPUS];       /* allowable mapping */
+    u32             ssidref;
 } dom0_getdomaininfo_t;
 
 #define DOM0_SETDOMAININFO      13
diff --git a/xen/include/public/policy_ops.h b/xen/include/public/policy_ops.h
new file mode 100644 (file)
index 0000000..6b55f76
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * policy_ops.h
+ * 
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License. 
+ *
+ * Process policy command requests from guest OS.
+ * access checked by policy; not restricted to DOM0
+ * 
+ */
+
+
+#ifndef __XEN_PUBLIC_POLICY_OPS_H__
+#define __XEN_PUBLIC_POLICY_OPS_H__
+
+#include "xen.h"
+#include "sched_ctl.h"
+
+/*
+ * Make sure you increment the interface version whenever you modify this file!
+ * This makes sure that old versions of policy tools will stop working in a
+ * well-defined way (rather than crashing the machine, for instance).
+ */
+#define POLICY_INTERFACE_VERSION   0xAAAA0001
+
+/************************************************************************/
+
+#define POLICY_SETPOLICY               4
+typedef struct {
+    /* IN variables. */
+    u16           policy_type;
+    u16                  padding1;
+    /* OUT variables */
+    void         *pushcache;
+    u16           pushcache_size;
+} PACKED policy_setpolicy_t;          
+
+
+#define POLICY_GETPOLICY               5
+typedef struct {
+    /* IN variables. */
+    u16           policy_type;
+    u16                  padding1;
+    /* OUT variables */
+    void         *pullcache;
+    u16           pullcache_size;
+} PACKED policy_getpolicy_t;       
+
+#define POLICY_DUMPSTATS               6
+typedef struct {
+    void         *pullcache;
+    u16           pullcache_size;
+} PACKED policy_dumpstats_t;            
+
+typedef struct {
+    u32 cmd;                          /* 0 */
+    u32 interface_version;            /* 4 */ /* POLICY_INTERFACE_VERSION */
+       union {                       /* 8 */
+        u32                     dummy[14];  /* 72bytes */
+       policy_setpolicy_t       setpolicy;
+        policy_getpolicy_t       getpolicy;
+       policy_dumpstats_t       dumpstats;
+    } PACKED u;
+} PACKED policy_op_t;            /* 80 bytes */
+
+#endif /* __XEN_PUBLIC_POLICY_OPS_H__ */
index 2fdd400e92d9c43e9e77a959a173ad02f53e5eed..8b183491a6f7856556c58d008dec8fdbd87061b0 100644 (file)
@@ -58,6 +58,7 @@
 #define __HYPERVISOR_boot_vcpu            24
 #define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
 #define __HYPERVISOR_mmuext_op            26
+#define __HYPERVISOR_policy_op           27
 
 /* 
  * VIRTUAL INTERRUPTS
index 35a3c36cab6a37c990e0e32d4c9a4e81dff04559..7649f1a450716280ac0821b20b29043248ae4be6 100644 (file)
@@ -137,6 +137,8 @@ struct domain
     cpumask_t        cpumask;
 
     struct arch_domain arch;
+
+    void *ssid; /* sHype security subject identifier */
 };
 
 struct domain_setup_info